Revert "Merge remote-tracking branch 'origin/GP-653_UserDefinedCspec--SQUASHED'"

This commit is contained in:
ghidra1
2021-04-30 10:34:54 -04:00
parent b7499e1bc1
commit a40370ab7a
108 changed files with 2000 additions and 8000 deletions
@@ -101,8 +101,8 @@ public class CallFixupAnalyzer extends AbstractAnalyzer {
if (mustFix) {
PcodeInjectLibrary snippetLibrary =
program.getCompilerSpec().getPcodeInjectLibrary();
InjectPayload callFixup =
snippetLibrary.getPayload(InjectPayload.CALLFIXUP_TYPE, callFixupApplied);
InjectPayload callFixup = snippetLibrary.getPayload(InjectPayload.CALLFIXUP_TYPE,
callFixupApplied, program, null);
boolean isfallthru = true;
if (callFixup != null) {
isfallthru = callFixup.isFallThru();
@@ -405,8 +405,8 @@ public class CallFixupAnalyzer extends AbstractAnalyzer {
}
}
program.getBookmarkManager()
.removeBookmarks(repairedCallLocations, BookmarkType.ERROR, monitor);
program.getBookmarkManager().removeBookmarks(repairedCallLocations, BookmarkType.ERROR,
monitor);
if (!clearInstSet.isEmpty()) {
// entries including data flow referenced from instructions will be repaired
@@ -449,7 +449,7 @@ public class CallFixupAnalyzer extends AbstractAnalyzer {
String[] callFixupNames = snippetLibrary.getCallFixupNames();
for (String fixupName : callFixupNames) {
InjectPayload payload =
snippetLibrary.getPayload(InjectPayload.CALLFIXUP_TYPE, fixupName);
snippetLibrary.getPayload(InjectPayload.CALLFIXUP_TYPE, fixupName, program, null);
List<String> callFixupTargets = ((InjectPayloadCallfixup) payload).getTargets();
for (String name : callFixupTargets) {
cachedTargetFixupMap.put(name, fixupName);
@@ -359,9 +359,6 @@ public class FunctionEditorDialog extends DialogComponentProvider implements Mod
}
private JComponent createCallFixupComboPanel() {
JPanel panel = new JPanel();
callFixupComboBox = new GComboBox<>();
String[] callFixupNames = model.getCallFixupNames();
@@ -380,8 +377,7 @@ public class FunctionEditorDialog extends DialogComponentProvider implements Mod
callFixupComboBox.setEnabled(false);
}
panel.add(callFixupComboBox);
return panel;
return callFixupComboBox;
}
private Component buildTable() {
@@ -405,9 +405,8 @@ public class SymbolicPropogator {
canceled = false;
// only stop flowing on unknown bad calls when the stack depth could be unknown
boolean callCouldCauseBadStackDepth = program.getCompilerSpec()
.getDefaultCallingConvention()
.getExtrapop() == PrototypeModel.UNKNOWN_EXTRAPOP;
boolean callCouldCauseBadStackDepth =
program.getCompilerSpec().getDefaultCallingConvention().getExtrapop() == PrototypeModel.UNKNOWN_EXTRAPOP;
while (!contextStack.isEmpty()) {
monitor.checkCanceled();
@@ -835,8 +834,8 @@ public class SymbolicPropogator {
try {
val1 = vContext.getValue(in[0], evaluator);
lval1 = vContext.getConstant(val1, evaluator);
vt = vContext.getVarnode(minInstrAddress.getAddressSpace().getSpaceID(),
lval1, 0);
vt = vContext.getVarnode(
minInstrAddress.getAddressSpace().getSpaceID(), lval1, 0);
makeReference(vContext, instruction, ptype, -1, vt,
instruction.getFlowType(), monitor);
}
@@ -874,8 +873,8 @@ public class SymbolicPropogator {
if (val1.isConstant()) {
// indirect target - assume single code space (same as instruction)
target = instruction.getAddress()
.getNewTruncatedAddress(val1.getOffset(), true);
target = instruction.getAddress().getNewTruncatedAddress(
val1.getOffset(), true);
}
else if (val1.isAddress()) {
// TODO: could this also occur if a memory location was copied ??
@@ -958,8 +957,8 @@ public class SymbolicPropogator {
case PcodeOp.CALLOTHER:
// HACK ALERT!
// if this is a segment op, emulate the segmenting for now.
String opName = this.program.getLanguage()
.getUserDefinedOpName((int) in[0].getOffset());
String opName = this.program.getLanguage().getUserDefinedOpName(
(int) in[0].getOffset());
if (opName.equals("segment") && in.length > 2) {
checkSegmented(out, in[1], in[2], mustClearAll);
}
@@ -1075,8 +1074,8 @@ public class SymbolicPropogator {
}
else if (!evaluator.followFalseConditionalBranches()) {
// pcode addresses are raw addresses, make sure address is in same instruction space
nextAddr = minInstrAddress.getAddressSpace()
.getOverlayAddress(in[0].getAddress());
nextAddr = minInstrAddress.getAddressSpace().getOverlayAddress(
in[0].getAddress());
pcodeIndex = ops.length; // break out of the processing
}
}
@@ -1203,8 +1202,8 @@ public class SymbolicPropogator {
case PcodeOp.INT_RIGHT:
val1 = vContext.getValue(in[0], false, evaluator);
val2 = vContext.getValue(in[1], false, evaluator);
lresult = vContext.getConstant(val1, evaluator) >> vContext
.getConstant(val2, evaluator);
lresult = vContext.getConstant(val1,
evaluator) >> vContext.getConstant(val2, evaluator);
result = vContext.createConstantVarnode(lresult, val1.getSize());
vContext.putValue(out, result, mustClearAll);
break;
@@ -1212,8 +1211,8 @@ public class SymbolicPropogator {
case PcodeOp.INT_SRIGHT:
val1 = vContext.getValue(in[0], true, evaluator);
val2 = vContext.getValue(in[1], false, evaluator);
lresult = vContext.getConstant(val1, evaluator) >>> vContext
.getConstant(val2, evaluator);
lresult = vContext.getConstant(val1,
evaluator) >>> vContext.getConstant(val2, evaluator);
result = vContext.createConstantVarnode(lresult, val1.getSize());
vContext.putValue(out, result, mustClearAll);
break;
@@ -1316,8 +1315,8 @@ public class SymbolicPropogator {
val2 = vContext.getValue(in[1], true, evaluator);
lval1 = vContext.getConstant(val1, evaluator);
lval2 = vContext.getConstant(val2, evaluator);
lresult = (vContext.getConstant(val1, evaluator) < vContext
.getConstant(val2, evaluator)) ? 1 : 0;
lresult = (vContext.getConstant(val1,
evaluator) < vContext.getConstant(val2, evaluator)) ? 1 : 0;
result = vContext.createConstantVarnode(lresult, val1.getSize());
vContext.putValue(out, result, mustClearAll);
break;
@@ -1335,8 +1334,8 @@ public class SymbolicPropogator {
case PcodeOp.INT_SLESSEQUAL:
val1 = vContext.getValue(in[0], true, evaluator);
val2 = vContext.getValue(in[1], true, evaluator);
lresult = (vContext.getConstant(val1, evaluator) <= vContext
.getConstant(val2, evaluator)) ? 1 : 0;
lresult = (vContext.getConstant(val1,
evaluator) <= vContext.getConstant(val2, evaluator)) ? 1 : 0;
result = vContext.createConstantVarnode(lresult, val1.getSize());
vContext.putValue(out, result, mustClearAll);
break;
@@ -1345,8 +1344,8 @@ public class SymbolicPropogator {
val1 = vContext.getValue(in[0], false, evaluator);
val2 = vContext.getValue(in[1], false, evaluator);
lresult = (vContext.getConstant(val1, evaluator) == vContext
.getConstant(val2, evaluator)) ? 1 : 0;
lresult = (vContext.getConstant(val1,
evaluator) == vContext.getConstant(val2, evaluator)) ? 1 : 0;
result = vContext.createConstantVarnode(lresult, val1.getSize());
vContext.putValue(out, result, mustClearAll);
break;
@@ -1354,8 +1353,8 @@ public class SymbolicPropogator {
case PcodeOp.INT_NOTEQUAL:
val1 = vContext.getValue(in[0], false, evaluator);
val2 = vContext.getValue(in[1], false, evaluator);
lresult = (vContext.getConstant(val1, evaluator) != vContext
.getConstant(val2, evaluator)) ? 1 : 0;
lresult = (vContext.getConstant(val1,
evaluator) != vContext.getConstant(val2, evaluator)) ? 1 : 0;
result = vContext.createConstantVarnode(lresult, val1.getSize());
vContext.putValue(out, result, mustClearAll);
break;
@@ -1572,7 +1571,7 @@ public class SymbolicPropogator {
PcodeInjectLibrary snippetLibrary = prog.getCompilerSpec().getPcodeInjectLibrary();
InjectPayload payload =
snippetLibrary.getPayload(InjectPayload.CALLFIXUP_TYPE, callFixupName);
snippetLibrary.getPayload(InjectPayload.CALLFIXUP_TYPE, callFixupName, prog, null);
if (payload == null) {
return null;
}
@@ -1599,7 +1598,7 @@ public class SymbolicPropogator {
PcodeInjectLibrary snippetLibrary = prog.getCompilerSpec().getPcodeInjectLibrary();
InjectPayload payload =
snippetLibrary.getPayload(InjectPayload.CALLMECHANISM_TYPE, injectionName);
snippetLibrary.getPayload(InjectPayload.CALLMECHANISM_TYPE, injectionName, prog, null);
if (payload == null) {
return null;
}
@@ -1844,14 +1843,14 @@ public class SymbolicPropogator {
// } else
if (!vContext.isStackSymbolicSpace(refLocation) && evaluator != null) {
Address constant = program.getAddressFactory()
.getAddress((int) targetSpaceID.getOffset(), offset);
Address constant = program.getAddressFactory().getAddress(
(int) targetSpaceID.getOffset(), offset);
Address newTarget = evaluator.evaluateConstant(vContext, instruction,
pcodeType, constant, 0, reftype);
if (newTarget != null) {
makeReference(vContext, instruction, Reference.MNEMONIC,
newTarget.getAddressSpace().getSpaceID(), newTarget.getOffset(), 0,
reftype, pcodeType, false, monitor);
newTarget.getAddressSpace().getSpaceID(), newTarget.getOffset(),
0, reftype, pcodeType, false, monitor);
return;
}
}
+10 -10
View File
@@ -120,7 +120,7 @@ task buildDecompilerHelpHtml(type: Exec) {
rm -f $installHelpPoint/topics/DecompilePlugin/*.html
echo '** Building html files **'
xsltproc --output $buildDir/decomp_noscaling.xml --stringparam profile.condition "noscaling" commonprofile.xsl decompileplugin.xml 2>&1
xsltproc --output $buildDir/decomp_noscaling.xml --stringparam profile.condition "noscaling" /usr/share/sgml/docbook/xsl-stylesheets/profiling/profile.xsl decompileplugin.xml 2>&1
xsltproc --stringparam base.dir ${installHelpPoint}/topics/DecompilePlugin/ --stringparam root.filename Decompiler decompileplugin_html.xsl $buildDir/decomp_noscaling.xml 2>&1
rm ${installHelpPoint}/topics/DecompilePlugin/Decompiler.html
sed -i -e '/Frontpage.css/ { p; s/Frontpage.css/languages.css/; }' ${installHelpPoint}/topics/DecompilePlugin/*.html 2>&1
@@ -175,19 +175,19 @@ task buildDecompilerHelpPdf(type: Exec) {
echo '** Checking if required executables are installed. **'
which fop 2>&1
which xsltproc 2>&1
rm -f $buildDir/decompileplugin.fo $buildDir/decompileplugin.pdf $buildDir/decompileplugin_withscaling.xml 2>&1
rm -rf $buildDir/images 2>&1
mkdir -p $buildDir/images 2>&1
cp $installHelpPoint/topics/DecompilePlugin/images/*.png $buildDir/images 2>&1
cp $installHelpPoint/topics/DecompilePlugin/images/*.gif $buildDir/images 2>&1
cp $installHelpPoint/shared/*.png $buildDir/images 2>&1
rm -f decompileplugin.fo decompileplugin.pdf decompileplugin_withscaling.xml 2>&1
rm -rf ./images 2>&1
mkdir -p ./images 2>&1
cp $installHelpPoint/topics/DecompilePlugin/images/*.png ./images 2>&1
cp $installHelpPoint/topics/DecompilePlugin/images/*.gif ./images 2>&1
cp $installHelpPoint/shared/*.png ./images 2>&1
echo '** Building decompileplugin.fo **'
xsltproc --output $buildDir/decompileplugin_withscaling.xml --stringparam profile.condition "withscaling" commonprofile.xsl decompileplugin.xml 2>&1
xsltproc --output $buildDir/decompileplugin.fo decompileplugin_pdf.xsl $buildDir/decompileplugin_withscaling.xml 2>&1
xsltproc --output ./decompileplugin_withscaling.xml --stringparam profile.condition "withscaling" /usr/share/sgml/docbook/xsl-stylesheets/profiling/profile.xsl decompileplugin.xml 2>&1
xsltproc --output ./decompileplugin.fo decompileplugin_pdf.xsl decompileplugin_withscaling.xml 2>&1
echo '** Building decompileplugin.pdf **'
fop $buildDir/decompileplugin.fo $buildDir/decompileplugin.pdf 2>&1
fop decompileplugin.fo decompileplugin.pdf 2>&1
echo '** Done. **'
"""
@@ -30,7 +30,6 @@ src/decompile/datatests/sbyte.xml||GHIDRA||||END|
src/decompile/datatests/threedim.xml||GHIDRA||||END|
src/decompile/datatests/twodim.xml||GHIDRA||||END|
src/decompile/datatests/wayoffarray.xml||GHIDRA||||END|
src/main/doc/commonprofile.xsl||GHIDRA||||END|
src/main/doc/cspec.xml||GHIDRA||||END|
src/main/doc/cspec_html.xsl||GHIDRA||||END|
src/main/doc/decompileplugin.xml||GHIDRA||||END|
@@ -15,17 +15,18 @@
*/
import ghidra.app.script.GhidraScript;
import ghidra.framework.options.Options;
import ghidra.program.database.ProgramCompilerSpec;
import ghidra.program.model.lang.BasicCompilerSpec;
public class TurnOnLanguage extends GhidraScript {
@Override
protected void run() throws Exception {
Options decompilerPropertyList =
currentProgram.getOptions(ProgramCompilerSpec.DECOMPILER_PROPERTY_LIST_NAME);
decompilerPropertyList.registerOption(ProgramCompilerSpec.DECOMPILER_OUTPUT_LANGUAGE,
ProgramCompilerSpec.DECOMPILER_OUTPUT_DEF, null,
ProgramCompilerSpec.DECOMPILER_OUTPUT_DESC);
Options decompilerPropertyList = currentProgram.getOptions(BasicCompilerSpec.DECOMPILER_PROPERTY_LIST_NAME);
decompilerPropertyList.registerOption(
BasicCompilerSpec.DECOMPILER_OUTPUT_LANGUAGE,
BasicCompilerSpec.DECOMPILER_OUTPUT_DEF,
null,
BasicCompilerSpec.DECOMPILER_OUTPUT_DESC);
}
}
@@ -1218,26 +1218,6 @@ 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>
@@ -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 store the return address
return_address = 3, ///< The memory is being used to pass back a return value from the sub-function
unknown_effect = 4 ///< An unknown effect (indicates the absence of an EffectRecord)
};
private:
@@ -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.clear(); // Strings aren't used again free memory
cspecxml.clear();
tspecxml.clear();
corespecxml.clear();
pspecxml = ""; // Strings aren't used again free memory
cspecxml = "";
tspecxml = "";
corespecxml = "";
}
void ArchitectureGhidra::postSpecFile(void)
@@ -82,8 +82,7 @@ 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
@@ -174,10 +174,6 @@ 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);
@@ -293,23 +293,6 @@ 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)
{
@@ -416,10 +399,9 @@ void PcodeInjectLibrarySleigh::restoreDebug(const Element *el)
s.unsetf(ios::dec | ios::hex | ios::oct);
s >> type;
int4 id = getPayloadId(type,name);
InjectPayloadDynamic *payload = dynamic_cast<InjectPayloadDynamic *>(getPayload(id));
if (payload == (InjectPayloadDynamic *)0) {
payload = forceDebugDynamic(id);
}
InjectPayloadDynamic *payload = (InjectPayloadDynamic *)getPayload(id);
if (payload->getSource() != "dynamic")
throw LowlevelError("Mismatch with debug inject XML");
payload->restoreEntry(subel);
}
}
@@ -91,7 +91,6 @@ 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);
@@ -216,10 +216,10 @@ void SegmentOp::restoreXml(const Element *el)
throw LowlevelError("Bad segment pattern tag: "+subel->getName());
}
if (injectId < 0)
throw LowlevelError("Missing <pcode> child in <segmentop> tag");
throw LowlevelError("Missing <execute> child in <segmentop> tag");
InjectPayload *payload = glb->pcodeinjectlib->getPayload(injectId);
if (payload->sizeOutput() != 1)
throw LowlevelError("<pcode> child of <segmentop> tag must declare one <output>");
throw LowlevelError("<execute> 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("<pcode> child of <segmentop> tag must declare one or two <input> tags");
throw LowlevelError("<execute> child of <segmentop> tag must declare one or two <input> tags");
}
/// \param g is the Architecture owning this set of jump assist scripts
@@ -127,12 +127,6 @@ 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);
@@ -1,6 +0,0 @@
<?xml version='1.0'?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:import href="http://docbook.sourceforge.net/release/xsl/current/profiling/profile.xsl"/>
</xsl:stylesheet>
@@ -2,7 +2,7 @@
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:import href="http://docbook.sourceforge.net/release/xsl/current/html/chunk.xsl"/>
<xsl:import href="/usr/share/sgml/docbook/xsl-stylesheets/html/chunk.xsl"/>
<xsl:param name="generate.toc">
article/appendix nop
File diff suppressed because it is too large Load Diff
@@ -2,7 +2,7 @@
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:import href="http://docbook.sourceforge.net/release/xsl/current/html/chunk.xsl"/>
<xsl:import href="/usr/share/sgml/docbook/xsl-stylesheets/html/chunk.xsl"/>
<xsl:include href="decompileplugin_common.xsl" />
@@ -2,7 +2,7 @@
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:import href="http://docbook.sourceforge.net/release/xsl/current/fo/docbook.xsl"/>
<xsl:import href="/usr/share/sgml/docbook/xsl-stylesheets/fo/docbook.xsl"/>
<xsl:include href="decompileplugin_common.xsl" />
@@ -16,6 +16,6 @@
<xsl:param name="admon.textlabel" select="0"/> <!-- Don't display title for important/note tags -->
<xsl:param name="admon.graphics.path" select="'../../../build/images'"/>
<xsl:param name="admon.graphics.path" select="'./images/'"/>
</xsl:stylesheet>
@@ -2,7 +2,7 @@
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:import href="http://docbook.sourceforge.net/release/xsl/current/html/docbook.xsl"/>
<xsl:import href="/usr/share/sgml/docbook/xsl-stylesheets/html/docbook.xsl"/>
<xsl:param name="generate.toc">
article/appendix nop
@@ -2,7 +2,7 @@
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:import href="http://docbook.sourceforge.net/release/xsl/current/html/chunk.xsl"/>
<xsl:import href="/usr/share/sgml/docbook/xsl-stylesheets/html/chunk.xsl"/>
<xsl:include href="pcoderef_common.xsl" />
@@ -2,7 +2,7 @@
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:import href="http://docbook.sourceforge.net/release/xsl/current/fo/docbook.xsl"/>
<xsl:import href="/usr/share/sgml/docbook/xsl-stylesheets/fo/docbook.xsl"/>
<xsl:template match="table" mode="label.markup"/>
@@ -2,7 +2,7 @@
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:import href="http://docbook.sourceforge.net/release/xsl/current/html/chunk.xsl"/>
<xsl:import href="/usr/share/sgml/docbook/xsl-stylesheets/html/chunk.xsl"/>
<xsl:include href="sleigh_common.xsl" />
@@ -2,7 +2,7 @@
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:import href="http://docbook.sourceforge.net/release/xsl/current/fo/docbook.xsl"/>
<xsl:import href="/usr/share/sgml/docbook/xsl-stylesheets/fo/docbook.xsl"/>
<xsl:include href="sleigh_common.xsl" />
@@ -62,7 +62,6 @@
target="help/topics/DecompilePlugin/DecompilerConcepts.html">
<tocdef id="ConceptPcode" sortgroup="a" text="P-code" target="help/topics/DecompilePlugin/DecompilerConcepts.html#ConceptPcode"/>
<tocdef id="ConceptHighFunction" sortgroup="b" text="The HighFunction" target="help/topics/DecompilePlugin/DecompilerConcepts.html#ConceptHighFunction"/>
<tocdef id="ConceptSpecification" sortgroup="c" text="SLEIGH Specification Files" target="help/topics/DecompilePlugin/DecompilerConcepts.html#ConceptSpecification"/>
</tocdef>
<tocdef id="Program Annotations Affecting the Decompiler"
sortgroup="b"
@@ -84,7 +83,6 @@
<tocdef id="AnalysisOptions" sortgroup="b" text="Analysis Options" target="help/topics/DecompilePlugin/DecompilerOptions.html#AnalysisOptions"/>
<tocdef id="DisplayOptions" sortgroup="c" text="Display Options" target="help/topics/DecompilePlugin/DecompilerOptions.html#DisplayOptions"/>
<tocdef id="ProgramOptions" sortgroup="d" text="Program Options" target="help/topics/DecompilePlugin/DecompilerOptions.html#ProgramOptions"/>
<tocdef id="ExtensionOptions" sortgroup="e" text="Specification Extensions" target="help/topics/DecompilePlugin/DecompilerOptions.html#ExtensionOptions"/>
</tocdef>
<tocdef id="Decompiler Window"
sortgroup="d"
@@ -93,10 +91,9 @@
<tocdef id="DecompilerDisplay" sortgroup="a" text="Display" target="help/topics/DecompilePlugin/DecompilerWindow.html#DecompilerDisplay"/>
<tocdef id="MainWindow" sortgroup="b" text="Main Window" target="help/topics/DecompilePlugin/DecompilerWindow.html#MainWindow"/>
<tocdef id="Snapshot" sortgroup="c" text="Snapshot Windows" target="help/topics/DecompilePlugin/DecompilerWindow.html#Snapshot"/>
<tocdef id="UndefinedFunction" sortgroup="d" text="Undefined Functions" target="help/topics/DecompilePlugin/DecompilerWindow.html#UndefinedFunction"/>
<tocdef id="ToolBar" sortgroup="e" text="Tool Bar" target="help/topics/DecompilePlugin/DecompilerWindow.html#ToolBar"/>
<tocdef id="MouseActions" sortgroup="f" text="Mouse Actions" target="help/topics/DecompilePlugin/DecompilerWindow.html#MouseActions"/>
<tocdef id="MenuActions" sortgroup="g" text="Pop-up Menu Actions" target="help/topics/DecompilePlugin/DecompilerWindow.html#MenuActions"/>
<tocdef id="ToolBar" sortgroup="d" text="Tool Bar" target="help/topics/DecompilePlugin/DecompilerWindow.html#ToolBar"/>
<tocdef id="MouseActions" sortgroup="e" text="Mouse Actions" target="help/topics/DecompilePlugin/DecompilerWindow.html#MouseActions"/>
<tocdef id="MenuActions" sortgroup="f" text="Pop-up Menu Actions" target="help/topics/DecompilePlugin/DecompilerWindow.html#MenuActions"/>
</tocdef>
</tocdef>
</tocref>
@@ -4,7 +4,7 @@
<title>Program Annotations Affecting the Decompiler</title>
<link rel="stylesheet" type="text/css" href="../../shared/Frontpage.css">
<link rel="stylesheet" type="text/css" href="../../shared/languages.css">
<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
<meta name="generator" content="DocBook XSL Stylesheets V1.78.1">
<link rel="home" href="Decompiler.html" title="Decompiler">
<link rel="up" href="Decompiler.html" title="Decompiler">
<link rel="prev" href="DecompilerConcepts.html" title="Decompiler Concepts">
@@ -983,8 +983,7 @@
The calling convention used by the function can be specified as part of the function prototype. The convention
is specified by name, referring to the formal <a class="xref" href="DecompilerConcepts.html#ConceptPrototypeModel" title="Prototype Model">&#8220;Prototype Model&#8221;</a> that describes how storage
locations are selected for individual parameters along with other information about how the compiler treats
the function. Available models are determined by the processor and compiler, but can be extended by the user.
See <a class="xref" href="DecompilerOptions.html#ExtensionOptions" title="Specification Extensions">&#8220;Specification Extensions&#8221;</a>.
the function.
</p>
<p>
In the absence of parameter and return value annotations, the decompiler will use the prototype model as
@@ -1043,8 +1042,7 @@
</p>
<p>
Call-fixups are specified by name. The name and associated p-code chunk are typically defined in the
<span class="emphasis"><em>compiler specification</em></span> for the Program. Users can extend the available set
of call-fixups. See <a class="xref" href="DecompilerOptions.html#ExtensionOptions" title="Specification Extensions">&#8220;Specification Extensions&#8221;</a>.
<span class="emphasis"><em>compiler specification</em></span> for the Program.
</p>
</dd>
</dl></div>
@@ -4,7 +4,7 @@
<title>Decompiler Concepts</title>
<link rel="stylesheet" type="text/css" href="../../shared/Frontpage.css">
<link rel="stylesheet" type="text/css" href="../../shared/languages.css">
<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
<meta name="generator" content="DocBook XSL Stylesheets V1.78.1">
<link rel="home" href="Decompiler.html" title="Decompiler">
<link rel="up" href="Decompiler.html" title="Decompiler">
<link rel="prev" href="DecompilerIntro.html" title="Decompiler">
@@ -183,7 +183,7 @@
<div class="informalexample">
<div class="table">
<a name="ops.htmltable"></a><p class="title"><b>Table . P-code Operations</b></p>
<div class="table-contents"><table width="90%" frame="box" rules="all" id="ops.htmltable">
<div class="table-contents"><table width="90%" frame="box" rules="all">
<col width="40%">
<col width="60%">
@@ -283,7 +283,7 @@
</p>
<div class="informalexample">
<div class="table">
<a name="ref.htmltable"></a><table width="90%" frame="box" rules="rows" id="ref.htmltable">
<a name="ref.htmltable"></a><table width="90%" frame="box" rules="rows">
<col width="25%">
<col width="25%">
<col width="50%">
@@ -725,35 +725,6 @@
<div class="sect3">
<div class="titlepage"><div><div><h4 class="title">
<a name="ConceptCallother"></a>User-defined P-code Operations - CALLOTHER</h4></div></div></div>
<p>
P-code allows for additional, processor specific, operations referred to
as <span class="emphasis"><em>user-defined</em></span> or CALLOTHER operations.
These may be defined as part of a Ghidra's specification for the processor and
are typically used as placeholders for what is otherwise unmodeled processor behavior.
Each CALLOTHER must have a unique name, and as a p-code operation, it still takes
varnode inputs and may produce a varnode output. But the exact affect of the operation is
not specified.
</p>
<p>
The decompiler treats a CALLOTHER operation as a black box. It will keep track of data
flowing into and out of the operation but won't simplify or transform it. In decompiler
output, a CALLOTHER is usually displayed using its unique name, with functional syntax
showing its inputs and output.
</p>
<p>
Ghidra or a user can provide the behavior details for a named CALLOTHER operation. The
details are provided as a sequence of p-code operations, referred to as a
<span class="bold"><strong>Callother-Fixup</strong></span>, which is substituted for the
CALLOTHER operation during decompilation, or by other Analyzers that use p-code.
Callother-Fixups are applied by Ghidra for specific processor or compiler variants,
and a user can choose to apply them to an individual Program. (See <a class="xref" href="DecompilerOptions.html#ExtensionOptions" title="Specification Extensions">&#8220;Specification Extensions&#8221;</a>)
</p>
</div>
<div class="sect3">
<div class="titlepage"><div><div><h4 class="title">
<a name="ConceptInternalFunctions"></a>Internal Decompiler Functions</h4></div></div></div>
<p>
@@ -1081,13 +1052,10 @@
use of multiple models. Subsequently, each distinct model has a name like <code class="code">__stdcall</code> or
<code class="code">__thiscall</code>. The decompiler makes use of the prototype model, as assigned to the function by the user or
discovered in some other way, when performing its analysis of parameters.
It is possible for users to extend the set of prototype models available to a Program,
see <a class="xref" href="DecompilerOptions.html#ExtensionOptions" title="Specification Extensions">&#8220;Specification Extensions&#8221;</a>.
</p>
<p>
A prototype model is typically used as a whole and is assigned by name to individual functions. But some of
the sub-concepts of the model may be relevant to reverse engineers. Concepts that a prototype
model encapsulates include:
the sub-concepts of the model may be relevant to reverse engineers.
</p>
<div class="sect3">
<div class="titlepage"><div><div><h4 class="title">
@@ -1139,150 +1107,5 @@
</div>
</div>
<div class="section">
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
<a name="ConceptSpecification"></a>SLEIGH Specification Files</h2></div></div></div>
<p>
SLEIGH is Ghidra's specification language for describing processor instructions.
Specification files are read in for a Program, and once configured, Ghidra's SLEIGH engine can:
</p>
<div class="informalexample">
<div class="itemizedlist"><ul class="itemizedlist compact" style="list-style-type: bullet; ">
<li class="listitem" style="list-style-type: disc">
Disassemble machine instructions from the underlying bytes and
</li>
<li class="listitem" style="list-style-type: disc">
Produce the raw p-code consumed by the decompiler and other analyzers.
</li>
</ul></div>
</div>
<p>
</p>
<p>
Specification files are selected based on the <span class="emphasis"><em>Language Id</em></span>
assigned to the Program at the time it is imported into Ghidra.
(See <a class="ulink" href="help/topics/ImporterPlugin/importer.htm" target="_top">Import Program</a>)
</p>
<div class="informalexample">
<div class="itemizedlist"><ul class="itemizedlist compact" style="list-style-type: none; ">
<li class="listitem" style="list-style-type: none"><code class="code">x86:LE:32:default:windows</code></li>
<li class="listitem" style="list-style-type: none"><code class="code">AARCH64:LE:64:default:v8A:default</code></li>
<li class="listitem" style="list-style-type: none"><code class="code">MIPS:BE:32:micro:default</code></li>
</ul></div>
</div>
<p>
A <span class="bold"><strong>Language Id</strong></span> is a label with these 5 formal fields, separated
by a ':' character:
</p>
<div class="informalexample">
<div class="itemizedlist"><ul class="itemizedlist compact" style="list-style-type: disc; ">
<li class="listitem">Processor family</li>
<li class="listitem">Endianess</li>
<li class="listitem">Size of the address bus</li>
<li class="listitem">Process variant</li>
<li class="listitem">Compiler producing the Program</li>
</ul></div>
</div>
<p>
A field with the value 'default' indicates either the preferred processor variant or the preferred compiler.
</p>
<p>
Within the Ghidra installation, specification files are stored based on the overarching
processor family, such as 'MIPS' or 'x86'. For a specific family, files are located under
</p>
<div class="informalexample">
<code class="code">&lt;Root&gt;/Ghidra/Processors/&lt;Family&gt;/data/languages</code>
</div>
<p>
where <code class="code">&lt;Root&gt;</code> represents the root directory of the Ghidra installation and
<code class="code">&lt;Family&gt;</code> is the processor family.
</p>
<p>
There are several types of specification files that are distinguishable by their suffix.
These include:
</p>
<div class="informalexample">
<div class="variablelist"><dl class="variablelist">
<dt><span class="term"><span class="bold"><strong>SLEIGH files</strong></span> - *.slaspec or *.sinc</span></dt>
<dd>
<p>
These are the human readable SLEIGH language files. A single specification is
rooted in one of the <code class="code">*.slaspec</code> files, which may recursively include
one or more <code class="code">*.sinc</code> files. The format of these files is described
in the document "SLEIGH: A Language for Rapid Processor Specification".
</p>
</dd>
<dt><span class="term"><span class="bold"><strong>Compiled SLEIGH files</strong></span> - *.sla</span></dt>
<dd>
<p>
This is a compiled form of a single SLEIGH specification. It is produced
automatically by Ghidra from the corresponding <code class="code">*.slaspec</code>.
</p>
</dd>
<dt><span class="term"><span class="bold"><strong>Compiler specification files</strong></span> - *.cspec</span></dt>
<dd>
<p>
These files contain configuration for a specific compiler. Analysis of Programs whose
executable content was produced using this compiler benefits from this information.
The file is an XML document with tags describing details of data organization and
other conventions used by the compiler. In particular, the compiler specification
contains tags:
</p>
<p>
</p>
<div class="itemizedlist"><ul class="itemizedlist compact" style="list-style-type: none; ">
<li class="listitem" style="list-style-type: none">&lt;prototype&gt; - describing a specific calling convention</li>
<li class="listitem" style="list-style-type: none">&lt;callfixup&gt; - describing a Call-fixup</li>
<li class="listitem" style="list-style-type: none">&lt;callotherfixup&gt; - describing a Callother-fixup</li>
</ul></div>
<p>
</p>
</dd>
<dt><span class="term"><span class="bold"><strong>Processor specification files</strong></span> - *.pspec</span></dt>
<dd>
<p>
These files contain configuration information that is specific to a particular
processor variant.
</p>
</dd>
</dl></div>
</div>
<p>
</p>
<div class="sect2">
<div class="titlepage"><div><div><h3 class="title">
<a name="ConceptModifySpec"></a>Modifying Specification Files</h3></div></div></div>
<p>
Changing any of the specification files described here is not recommended.
To make additions to either the <span class="emphasis"><em>compiler specification</em></span>
or the <span class="emphasis"><em>processor specification</em></span> files, see
<a class="xref" href="DecompilerOptions.html#ExtensionOptions" title="Specification Extensions">&#8220;Specification Extensions&#8221;</a>, which describes a safe and portable way
to add specific elements.
</p>
<div class="warning" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Warning">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Warning]" src="../../shared/warning.png"></td>
<th align="left"></th>
</tr>
<tr><td align="left" valign="top">
Making modifications to specification files within a Ghidra installation is possible,
but any analysis results obtained will likely not be portable to other installations.
In particular, saving a Program from a modified Ghidra and then reopening it using
an unmodified installation may corrupt the Program database.
</td></tr>
</table></div>
<p>
When Ghidra starts, it checks for changes to <code class="code">*.slaspec</code>
and <code class="code">*.sinc</code> files and will rebuild the corresponding
<code class="code">*.sla</code> file automatically. Also, specification files are read again when
Ghidra restarts. So analysts can and do make changes to these files.
However they need to be prepared to view any results as temporary and
should backup their installation and specific Programs being analyzed.
</p>
</div>
</div>
</div></body>
</html>
@@ -4,7 +4,7 @@
<title>Decompiler</title>
<link rel="stylesheet" type="text/css" href="../../shared/Frontpage.css">
<link rel="stylesheet" type="text/css" href="../../shared/languages.css">
<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
<meta name="generator" content="DocBook XSL Stylesheets V1.78.1">
<link rel="home" href="Decompiler.html" title="Decompiler">
<link rel="up" href="Decompiler.html" title="Decompiler">
<link rel="prev" href="Decompiler.html" title="Decompiler">
@@ -4,7 +4,7 @@
<title>Decompiler Options</title>
<link rel="stylesheet" type="text/css" href="../../shared/Frontpage.css">
<link rel="stylesheet" type="text/css" href="../../shared/languages.css">
<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
<meta name="generator" content="DocBook XSL Stylesheets V1.78.1">
<link rel="home" href="Decompiler.html" title="Decompiler">
<link rel="up" href="Decompiler.html" title="Decompiler">
<link rel="prev" href="DecompilerAnnotations.html" title="Program Annotations Affecting the Decompiler">
@@ -42,17 +42,14 @@
<p>
</p>
<p>
Options that are specific to the particular Program being analyzed are accessed by
selecting the Code Browser menu
Another source of options can be accessed by selecting the Code Browser menu
</p>
<div class="informalexample">
<span class="bold"><strong>Edit -&gt; Options for &lt;Program&gt;</strong></span>
</div>
<p>
Picking the <span class="emphasis"><em>Decompiler</em></span> tab shows <a class="xref" href="DecompilerOptions.html#ProgramOptions" title="Program Options">&#8220;Program Options&#8221;</a>
that only affect the decompiler. Picking the <a class="xref" href="DecompilerOptions.html#ExtensionOptions" title="Specification Extensions">&#8220;Specification Extensions&#8221;</a> tab
shows a table of the available prototype models, call-fixups, and callother-fixups. These
affect more than just the decompiler but are also documented here.
and the picking the <span class="emphasis"><em>Decompiler</em></span> tab. These <a class="xref" href="DecompilerOptions.html#ProgramOptions" title="Program Options">&#8220;Program Options&#8221;</a>
are specific to the particular Program being analyzed.
</p>
</div>
<div class="section">
@@ -576,8 +573,7 @@
<a name="ProgramOptions"></a>Program Options</h2></div></div></div>
<p>
Changes to these options affect only the decompiler and only for
the current Program being analyzed.
Changes to these options affect only the current Program being analyzed.
</p>
<p>
</p>
@@ -599,284 +595,6 @@
<p>
</p>
</div>
<div class="section">
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
<a name="ExtensionOptions"></a>Specification Extensions</h2></div></div></div>
<p>
This tab displays elements from the Program's <span class="emphasis"><em>compiler specification</em></span> and
<span class="emphasis"><em>processor specification</em></span> and allows the user to add or remove
<span class="bold"><strong>extensions</strong></span>, including prototype models, call-fixups, and
callother-fixups.
</p>
<p>
Every program has a <span class="emphasis"><em>core</em></span> set of specification elements,
loaded from the <a class="xref" href="DecompilerConcepts.html#ConceptSpecification" title="SLEIGH Specification Files">&#8220;SLEIGH Specification Files&#8221;</a>, that cannot
be modified or removed. Extensions, however, can be added to this core specification. Any extension
imported from this dialog is directly associated with the active Program and is stored permanently
with it.
</p>
<p>
Users can change or reimport an extension, if new information points to a better definition.
Users have full control over an extension, and unlike a core element, can tailor it specifically
to the Program.
</p>
<p>
This options tab presents a table of all specification elements.
Each element, whether core or an extension, is displayed on a separate row with three columns:
</p>
<div class="informalexample">
<div class="itemizedlist"><ul class="itemizedlist compact" style="list-style-type: none; ">
<li class="listitem" style="list-style-type: none">
<span class="bold"><strong>Extension Type</strong></span> - indicating the type of element</li>
<li class="listitem" style="list-style-type: none">
<span class="bold"><strong>Name</strong></span> - showing the formal name of the element</li>
<li class="listitem" style="list-style-type: none">
<span class="bold"><strong>Status</strong></span> - indicating whether the element is core or an extension</li>
</ul></div>
</div>
<p>
The core elements of the specification have a blank Status column, and any extension
is labeled either as "extension" or "override".
</p>
<div class="sect2">
<div class="titlepage"><div><div><h3 class="title">
<a name="ExtendTypes"></a>Extension Types</h3></div></div></div>
<p>
Each of the element types described here represents an XML tag of the same name, which, if
present in the table, must either be in the <span class="emphasis"><em>compiler specification</em></span> file,
the <span class="emphasis"><em>processor specification</em></span> file, or provided to Ghidra as an
import document.
</p>
<div class="informalexample">
<div class="variablelist"><dl class="variablelist">
<dt><span class="term"><span class="bold"><strong>prototype</strong></span></span></dt>
<dd>
<p>
This element is a <a class="xref" href="DecompilerConcepts.html#ConceptPrototypeModel" title="Prototype Model">&#8220;Prototype Model&#8221;</a> that holds a specific named set
of parameter passing details. It
can be applied to individual functions by name, typically via the "Calling Convention" menu
in the <a class="ulink" href="help/topics/FunctionPlugin/Variables.htm#Edit_Function" target="_top">Function Editor Dialog</a>.
See the documentation on <a class="xref" href="DecompilerAnnotations.html#AnnotePrototype" title="Function Prototypes">&#8220;Function Prototypes&#8221;</a> for how they affect decompilation.
</p>
<p>
The XML tag, <code class="code">&lt;prototype&gt;</code> always has a <span class="bold"><strong>name</strong></span> attribute
that defines the formal name of the prototype model, which must be unique across all models.
</p>
<pre class="programlisting">
&lt;prototype name="__stdcall" extrapop="unknown" stackshift="4"&gt;
&lt;input&gt;
&lt;pentry minsize="1" maxsize="500" align="4"&gt;
&lt;addr offset="4" space="stack"/&gt;
&lt;/pentry&gt;
&lt;/input&gt;
&lt;output&gt;
...
</pre>
<p>
</p>
</dd>
<dt><span class="term"><span class="bold"><strong>callfixup</strong></span></span></dt>
<dd>
<p>
This element is a Call-fixup, which can be used to substitute a specific p-code
sequence for CALL instructions during decompilation, as described in
<a class="xref" href="DecompilerAnnotations.html#AnnotePrototype" title="Function Prototypes">&#8220;Function Prototypes&#8221;</a>.
</p>
<p>
The <code class="code">&lt;callfixup&gt;</code> tag has a <span class="bold"><strong>name</strong></span>
attribute listing the formal name, which must be unique across all call-fixups.
</p>
<pre class="programlisting">
&lt;callfixup name="EH_prolog3"&gt;
&lt;pcode&gt;
&lt;body&gt;&lt;![CDATA&lt;
EBP = ESP + 4;
tmp = * EBP;
ESP = ESP - tmp;
ESP = ESP - 24;
]]&gt;&lt;/body&gt;
&lt;/pcode&gt;
&lt;/callfixup&gt;
</pre>
<p>
</p>
</dd>
<dt><span class="term"><span class="bold"><strong>callotherfixup</strong></span></span></dt>
<dd>
<p>
This element is a Callother-fixup, which can be used to substitute a specific p-code
sequence for CALLOTHER p-code operations. A CALLOTHER
is a black-box, or unspecified p-code operation, see <a class="xref" href="DecompilerConcepts.html#ConceptCallother" title="User-defined P-code Operations - CALLOTHER">&#8220;User-defined P-code Operations - CALLOTHER&#8221;</a>.
</p>
<p>
The <code class="code">&lt;callotherfixup&gt;</code> tag has a
<span class="bold"><strong>targetop</strong></span> attribute which lists the
name of the particular CALLOTHER operation it substitutes for.
</p>
<pre class="programlisting">
&lt;callotherfixup targetop="dynamicPush"&gt;
&lt;pcode&gt;
&lt;input name="amount"/&gt;
&lt;body&gt;&lt;![CDATA[
RSP = RSP + amount;
]]&gt;&lt;/body&gt;
&lt;/pcode&gt;
&lt;/callotherfixup&gt;
</pre>
<p>
</p>
</dd>
</dl></div>
</div>
<p>
</p>
</div>
<div class="sect2">
<div class="titlepage"><div><div><h3 class="title">
<a name="ExtendStatus"></a>Status</h3></div></div></div>
<p>
The Status column labels an element as either a core specification
or an extension; it also gives an indication of whether the element
is about to be installed or removed.
</p>
<p>
With no changes pending, the column will show one of the three main values:
</p>
<div class="informalexample">
<div class="variablelist"><dl class="variablelist">
<dt><span class="term"><span class="emphasis"><em>&lt;blank&gt;</em></span></span></dt>
<dd>
<p>
A blank Status column indicates that the element is a core part of the
specification, originating from one of the <span class="emphasis"><em>specification files</em></span>.
These elements cannot be changed or removed.
</p>
</dd>
<dt><span class="term"><span class="bold"><strong>extension</strong></span></span></dt>
<dd>
<p>
Indicates that the element is a program specific extension that has been
added to the specification.
</p>
</dd>
<dt><span class="term"><span class="bold"><strong>override</strong></span></span></dt>
<dd>
<p>
Indicates that the element, which must be a <span class="bold"><strong>callotherfixup</strong></span>,
is an extension that overrides a core element with the same target. The extension
effectively replaces the p-code injection of the core element with a user supplied one.
If this type of extension is later removed, the core element becomes active again.
</p>
</dd>
</dl></div>
</div>
<p>
</p>
<p>
If the user has either imported additional extensions or selected an extensions for removal but
has not yet clicked the <span class="emphasis"><em>Apply</em></span> button in the Options dialog, the Status column
may show one of the following values, indicating a pending change.
</p>
<div class="informalexample">
<div class="variablelist"><dl class="variablelist">
<dt><span class="term"><span class="bold"><strong>install</strong></span></span></dt>
<dd>
<p>
Indicates a new extension that will be installed.
</p>
</dd>
<dt><span class="term"><span class="bold"><strong>remove</strong></span></span></dt>
<dd>
<p>
Indicates an extension that is about to be removed.
</p>
</dd>
<dt><span class="term"><span class="bold"><strong>replace</strong></span></span></dt>
<dd>
<p>
Indicates a new extension that will replace a current
extension with the same name.
</p>
</dd>
<dt><span class="term"><span class="bold"><strong>override pending</strong></span></span></dt>
<dd>
<p>
Indicates a new extension that will override a core element when
it is installed.
</p>
</dd>
</dl></div>
</div>
<p>
</p>
</div>
<div class="sect2">
<div class="titlepage"><div><div><h3 class="title">
<a name="ExtendImport"></a>Importing a New Extension</h3></div></div></div>
<p>
The <span class="emphasis"><em>Import</em></span> button at the bottom of the
"Specification Extensions" pane allows the user to import one of the
three element types, <span class="bold"><strong>prototype</strong></span>,
<span class="bold"><strong>callfixup</strong></span>, or <span class="bold"><strong>callotherfixup</strong></span>,
into the program as a new extension.
The user must supply a properly formed XML document, as a file, that fully describes the new
extension. Clicking the <span class="emphasis"><em>Import</em></span> button brings up a File Chooser dialog,
from which the user must select their prepared XML file. Once <span class="emphasis"><em>Ok</em></span> is
clicked, the file is read in and validated. If there are any problems with the validation, or if
the new extension's name collides with a core element, the import does not succeed and
an error message will be displayed. Otherwise, the import is accepted, and the table is updated
to indicate the pending change.
</p>
<p>
The final change to the program, installing the new extension, will not happen until the
<span class="emphasis"><em>Apply</em></span> button, at the bottom of the Options dialog, is clicked.
</p>
<p>
The XML file describing the extension <span class="emphasis"><em>must</em></span> have one of the tags,
<code class="code">&lt;prototype&gt;</code>, <code class="code">&lt;callfixup&gt;</code>, or <code class="code">&lt;callotherfixup&gt;</code>,
as its single root element. Users can find numerous examples within the compiler
and processor specification files that come as part of Ghidra's installation.
See <a class="xref" href="DecompilerConcepts.html#ConceptSpecification" title="SLEIGH Specification Files">&#8220;SLEIGH Specification Files&#8221;</a>.
</p>
<p>
In the case of <span class="bold"><strong>prototype</strong></span> and <span class="bold"><strong>callfixup</strong></span>
elements, extensions cannot replace existing core elements, so the new extension <span class="emphasis"><em>must not</em></span>
have a name that matches an existing core element. If a new <span class="bold"><strong>callotherfixup</strong></span>
extension has a targetop that matches a core element, the extension is automatically treated as an override.
</p>
<p>
Existing extensions can be replaced simply by importing a new extension with the same name or targetop.
</p>
</div>
<div class="sect2">
<div class="titlepage"><div><div><h3 class="title">
<a name="ExtendRemove"></a>Removing an Extension</h3></div></div></div>
<p>
The <span class="emphasis"><em>Remove</em></span> button at the bottom of the "Specification Extensions" pane allows
the user to remove a previously installed extension. A row from the table is selected first, which
must have a Status of <span class="bold"><strong>extension</strong></span> or <span class="bold"><strong>override</strong></span>.
Core elements of the specification cannot be removed.
Clicking the <span class="emphasis"><em>Remove</em></span> button brings up a confirmation dialog, and if
<span class="emphasis"><em>Ok</em></span> is clicked, the selected extension is marked for removal. The Status of the row
changes to <span class="bold"><strong>remove</strong></span>, reflecting this.
</p>
<p>
The final change to the program, removing the extension, will not happen until the
<span class="emphasis"><em>Apply</em></span> button, at the bottom of the Options dialog, is clicked.
</p>
<p>
If a <span class="bold"><strong>prototype</strong></span> or <span class="bold"><strong>callfixup</strong></span> is removed,
all functions are checked to see if they have the matching calling convention or call-fixup set.
A function with matching calling convention is changed to have the <span class="emphasis"><em>default</em></span> convention, which is always a core element.
A function with matching call-fixup is changed to have no call-fixup.
</p>
</div>
</div>
</div></body>
</html>
@@ -4,7 +4,7 @@
<title>Decompiler Window</title>
<link rel="stylesheet" type="text/css" href="../../shared/Frontpage.css">
<link rel="stylesheet" type="text/css" href="../../shared/languages.css">
<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
<meta name="generator" content="DocBook XSL Stylesheets V1.78.1">
<link rel="home" href="Decompiler.html" title="Decompiler">
<link rel="up" href="Decompiler.html" title="Decompiler">
<link rel="prev" href="DecompilerOptions.html" title="Decompiler Options">
@@ -222,7 +222,7 @@ public class DecompInterface {
(SleighLanguageDescription) pcodelanguage.getLanguageDescription();
ResourceFile pspecfile = sleighdescription.getSpecFile();
String pspecxml = fileToString(pspecfile);
String cspecxml = compilerSpec.getXMLString();
String cspecxml = compilerSpec.getCompilerSpecString();
decompCallback.setNativeMessage(null);
decompProcess.registerProgram(decompCallback, pspecxml, cspecxml, tspec, coretypes);
@@ -232,9 +232,8 @@ public class DecompInterface {
}
if (xmlOptions != null) {
decompProcess.setMaxResultSize(xmlOptions.getMaxPayloadMBytes());
if (!decompProcess.sendCommand1Param("setOptions", xmlOptions.getXML(this))
.toString()
.equals("t")) {
if (!decompProcess.sendCommand1Param("setOptions",
xmlOptions.getXML(this)).toString().equals("t")) {
throw new IOException("Did not accept decompiler options");
}
}
@@ -242,16 +241,14 @@ public class DecompInterface {
throw new IOException("Decompile action not specified");
}
if (!actionname.equals("decompile")) {
if (!decompProcess.sendCommand2Params("setAction", actionname, "")
.toString()
.equals("t")) {
if (!decompProcess.sendCommand2Params("setAction", actionname, "").toString().equals(
"t")) {
throw new IOException("Could not set decompile action");
}
}
if (!printSyntaxTree) {
if (!decompProcess.sendCommand2Params("setAction", "", "notree")
.toString()
.equals("t")) {
if (!decompProcess.sendCommand2Params("setAction", "", "notree").toString().equals(
"t")) {
throw new IOException("Could not turn off syntax tree");
}
}
@@ -261,16 +258,14 @@ public class DecompInterface {
}
}
if (sendParamMeasures) {
if (!decompProcess.sendCommand2Params("setAction", "", "parammeasures")
.toString()
.equals("t")) {
if (!decompProcess.sendCommand2Params("setAction", "",
"parammeasures").toString().equals("t")) {
throw new IOException("Could not turn on sending of parameter measures");
}
}
if (jumpLoad) {
if (!decompProcess.sendCommand2Params("setAction", "", "jumpload")
.toString()
.equals("t")) {
if (!decompProcess.sendCommand2Params("setAction", "", "jumpload").toString().equals(
"t")) {
throw new IOException("Could not turn on jumptable loads");
}
}
@@ -414,9 +409,8 @@ public class DecompInterface {
}
try {
verifyProcess();
return decompProcess.sendCommand2Params("setAction", actionstring, "")
.toString()
.equals("t");
return decompProcess.sendCommand2Params("setAction", actionstring,
"").toString().equals("t");
}
catch (IOException e) {
// don't care
@@ -452,9 +446,8 @@ public class DecompInterface {
String printstring = val ? "tree" : "notree";
try {
verifyProcess();
return decompProcess.sendCommand2Params("setAction", "", printstring)
.toString()
.equals("t");
return decompProcess.sendCommand2Params("setAction", "", printstring).toString().equals(
"t");
}
catch (IOException e) {
// don't care
@@ -491,9 +484,8 @@ public class DecompInterface {
String printstring = val ? "c" : "noc";
try {
verifyProcess();
return decompProcess.sendCommand2Params("setAction", "", printstring)
.toString()
.equals("t");
return decompProcess.sendCommand2Params("setAction", "", printstring).toString().equals(
"t");
}
catch (IOException e) {
// don't care
@@ -529,9 +521,8 @@ public class DecompInterface {
String printstring = val ? "parammeasures" : "noparammeasures";
try {
verifyProcess();
return decompProcess.sendCommand2Params("setAction", "", printstring)
.toString()
.equals("t");
return decompProcess.sendCommand2Params("setAction", "", printstring).toString().equals(
"t");
}
catch (IOException e) {
// don't care
@@ -560,9 +551,8 @@ public class DecompInterface {
String jumpstring = val ? "jumpload" : "nojumpload";
try {
verifyProcess();
return decompProcess.sendCommand2Params("setAction", "", jumpstring)
.toString()
.equals("t");
return decompProcess.sendCommand2Params("setAction", "", jumpstring).toString().equals(
"t");
}
catch (IOException e) {
// don't care
@@ -598,9 +588,8 @@ public class DecompInterface {
try {
verifyProcess();
decompProcess.setMaxResultSize(xmlOptions.getMaxPayloadMBytes());
return decompProcess.sendCommand1Param("setOptions", xmloptions.getXML(this))
.toString()
.equals("t");
return decompProcess.sendCommand1Param("setOptions",
xmloptions.getXML(this)).toString().equals("t");
}
catch (IOException e) {
// don't care
@@ -718,10 +707,9 @@ public class DecompInterface {
debug.setFunction(func);
}
decompCallback.setFunction(func, funcEntry, debug);
StringBuilder addrBuf = new StringBuilder();
AddressXML.buildXML(addrBuf, funcEntry);
String addrstring = Varnode.buildXMLAddress(funcEntry);
verifyProcess();
res = decompProcess.sendCommand1ParamTimeout("decompileAt", addrBuf.toString(),
res = decompProcess.sendCommand1ParamTimeout("decompileAt", addrstring.toString(),
timeoutSecs);
decompileMessage = decompCallback.getNativeMessage();
}
@@ -55,7 +55,6 @@ import ghidra.util.xml.XmlUtilities;
public class DecompileCallback {
public final static int MAX_SYMBOL_COUNT = 16;
/**
* Data returned for a query about strings
*/
@@ -71,7 +70,6 @@ public class DecompileCallback {
private Function cachedFunction;
private AddressSet undefinedBody;
private Address funcEntry;
private AddressSpace overlaySpace; // non-null if function being decompiled is in an overlay
private int default_extrapop;
private Language pcodelanguage;
private CompilerSpec pcodecompilerspec;
@@ -127,8 +125,6 @@ public class DecompileCallback {
undefinedBody = new AddressSet(func.getBody());
}
funcEntry = entry;
AddressSpace spc = funcEntry.getAddressSpace();
overlaySpace = spc.isOverlaySpace() ? spc : null;
debug = dbg;
if (debug != null) {
debug.setPcodeDataTypeManager(dtmanage);
@@ -157,6 +153,19 @@ public class DecompileCallback {
nativeMessage = msg;
}
public synchronized int readXMLSize(String addrxml) {
int attrstart = addrxml.indexOf("size=\"");
if (attrstart >= 4) {
attrstart += 6;
int attrend = addrxml.indexOf('\"', attrstart);
if (attrend > attrstart) {
int size = SpecXmlUtils.decodeInt(addrxml.substring(attrstart, attrend));
return size;
}
}
return 0;
}
public synchronized ArrayList<String> readXMLNameList(String xml) throws PcodeXMLException {
try {
NameListHandler nmHandler = new NameListHandler();
@@ -173,11 +182,9 @@ public class DecompileCallback {
public byte[] getBytes(String addrxml) {
try {
Address addr = AddressXML.readXML(addrxml, addrfactory);
int size = AddressXML.readXMLSize(addrxml);
if (overlaySpace != null) {
addr = overlaySpace.getOverlayAddress(addr);
}
int size = readXMLSize(addrxml);
Address addr;
addr = Varnode.readXMLAddress(addrxml, addrfactory, funcEntry.getAddressSpace());
if (addr == Address.NO_ADDRESS) {
throw new PcodeXMLException("Address does not physically map");
}
@@ -223,10 +230,7 @@ public class DecompileCallback {
Address addr;
int flags;
try {
addr = AddressXML.readXML(addrstring, addrfactory);
if (overlaySpace != null) {
addr = overlaySpace.getOverlayAddress(addr);
}
addr = Varnode.readXMLAddress(addrstring, addrfactory, funcEntry.getAddressSpace());
}
catch (PcodeXMLException e) {
Msg.error(this, "Decompiling " + funcEntry + ": " + e.getMessage());
@@ -266,10 +270,7 @@ public class DecompileCallback {
public PackedBytes getPcodePacked(String addrstring) {
Address addr = null;
try {
addr = AddressXML.readXML(addrstring, addrfactory);
if (overlaySpace != null) {
addr = overlaySpace.getOverlayAddress(addr);
}
addr = Varnode.readXMLAddress(addrstring, addrfactory, funcEntry.getAddressSpace());
}
catch (PcodeXMLException e) {
Msg.error(this, "Decompiling " + funcEntry + ": " + e.getMessage());
@@ -292,9 +293,8 @@ public class DecompileCallback {
}
}
PackedBytes pcode = instr.getPrototype()
.getPcodePacked(instr.getInstructionContext(),
new InstructionPcodeOverride(instr), uniqueFactory);
PackedBytes pcode = instr.getPrototype().getPcodePacked(instr.getInstructionContext(),
new InstructionPcodeOverride(instr), uniqueFactory);
return pcode;
}
@@ -346,7 +346,7 @@ public class DecompileCallback {
public String getPcodeInject(String nm, String context, int type) {
PcodeInjectLibrary snippetLibrary = pcodecompilerspec.getPcodeInjectLibrary();
InjectPayload payload = snippetLibrary.getPayload(type, nm);
InjectPayload payload = snippetLibrary.getPayload(type, nm, program, context);
if (payload == null) {
Msg.warn(this, "Decompiling " + funcEntry + ", no pcode inject with name: " + nm);
return null; // No fixup associated with this name
@@ -381,8 +381,8 @@ public class DecompileCallback {
con.nextAddr = con.baseAddr.add(fallThruOffset);
con.refAddr = null;
for (Reference ref : program.getReferenceManager()
.getReferencesFrom(con.baseAddr)) {
for (Reference ref : program.getReferenceManager().getReferencesFrom(
con.baseAddr)) {
if (ref.isPrimary() && ref.getReferenceType().isCall()) {
con.refAddr = ref.getToAddress();
break;
@@ -487,10 +487,7 @@ public class DecompileCallback {
public String getSymbol(String addrstring) { // Return first symbol name at this address
Address addr;
try {
addr = AddressXML.readXML(addrstring, addrfactory);
if (overlaySpace != null) {
addr = overlaySpace.getOverlayAddress(addr);
}
addr = Varnode.readXMLAddress(addrstring, addrfactory, funcEntry.getAddressSpace());
}
catch (PcodeXMLException e) {
Msg.error(this, "Decompiling " + funcEntry + ": " + e.getMessage());
@@ -630,8 +627,8 @@ public class DecompileCallback {
buf.append("<comment");
SpecXmlUtils.encodeStringAttribute(buf, "type", "header");
buf.append(">\n");
AddressXML.buildXML(buf, addr);
AddressXML.buildXML(buf, addr);
buf.append(Varnode.buildXMLAddress(addr));
buf.append(Varnode.buildXMLAddress(addr));
buf.append("\n<text>");
SpecXmlUtils.xmlEscape(buf, text);
buf.append("</text>\n");
@@ -683,8 +680,8 @@ public class DecompileCallback {
buf.append("<comment");
SpecXmlUtils.encodeStringAttribute(buf, "type", typename);
buf.append(">\n");
AddressXML.buildXML(buf, addr);
AddressXML.buildXML(buf, commaddr);
buf.append(Varnode.buildXMLAddress(addr));
buf.append(Varnode.buildXMLAddress(commaddr));
buf.append("\n<text>");
SpecXmlUtils.xmlEscape(buf, text);
buf.append("</text>\n");
@@ -704,10 +701,7 @@ public class DecompileCallback {
public String getMappedSymbolsXML(String addrstring) { // Return XML describing data or functions at addr
Address addr;
try {
addr = AddressXML.readXML(addrstring, addrfactory);
if (overlaySpace != null) {
addr = overlaySpace.getOverlayAddress(addr);
}
addr = Varnode.readXMLAddress(addrstring, addrfactory, funcEntry.getAddressSpace());
if (addr == Address.NO_ADDRESS) {
// Unknown spaces may result from "spacebase" registers defined in cspec
return null;
@@ -749,10 +743,7 @@ public class DecompileCallback {
public String getExternalRefXML(String addrstring) { // Return any external reference at addr
Address addr;
try {
addr = AddressXML.readXML(addrstring, addrfactory);
if (overlaySpace != null) {
addr = overlaySpace.getOverlayAddress(addr);
}
addr = Varnode.readXMLAddress(addrstring, addrfactory, funcEntry.getAddressSpace());
}
catch (PcodeXMLException e) {
Msg.error(this, "Decompiling " + funcEntry + ": " + e.getMessage());
@@ -801,7 +792,6 @@ public class DecompileCallback {
Namespace namespc = funcSymbol.getNamespace();
if (debug != null) {
debug.getFNTypes(hfunc);
debug.addPossiblePrototypeExtension(func);
}
return buildResult(funcSymbol, namespc);
}
@@ -839,8 +829,8 @@ public class DecompileCallback {
public String getRegisterName(String addrstring) {
try {
Address addr = AddressXML.readXML(addrstring, addrfactory);
int size = AddressXML.readXMLSize(addrstring);
Address addr = Varnode.readXMLAddress(addrstring, addrfactory, null);
int size = readXMLSize(addrstring);
Register reg = pcodelanguage.getRegister(addr, size);
if (reg == null) {
return null;
@@ -857,10 +847,7 @@ public class DecompileCallback {
public String getTrackedRegisters(String addrstring) {
Address addr;
try {
addr = AddressXML.readXML(addrstring, addrfactory);
if (overlaySpace != null) {
addr = overlaySpace.getOverlayAddress(addr);
}
addr = Varnode.readXMLAddress(addrstring, addrfactory, funcEntry.getAddressSpace());
}
catch (PcodeXMLException e) {
Msg.error(this, "Decompiling " + funcEntry + ": " + e.getMessage());
@@ -871,7 +858,7 @@ public class DecompileCallback {
StringBuilder stringBuf = new StringBuilder();
stringBuf.append("<tracked_pointset");
AddressXML.appendAttributes(stringBuf, addr);
Varnode.appendSpaceOffset(stringBuf, addr);
stringBuf.append(">\n");
for (Register reg : context.getRegisters()) {
if (reg.isProcessorContext()) {
@@ -1033,8 +1020,8 @@ public class DecompileCallback {
if (entry.getAddressSpace().equals(addr.getAddressSpace())) {
long diff = addr.getOffset() - entry.getOffset();
if ((diff >= 0) && (diff < 8)) {
HighFunction hfunc =
new HighFunction(func, pcodelanguage, pcodecompilerspec, dtmanage);
HighFunction hfunc = new HighFunction(func, pcodelanguage, pcodecompilerspec,
dtmanage);
int extrapop = getExtraPopOverride(func, addr);
hfunc.grabFromFunction(extrapop, includeDefaultNames,
@@ -1044,7 +1031,6 @@ public class DecompileCallback {
Namespace namespc = functionSymbol.getNamespace();
if (debug != null) {
debug.getFNTypes(hfunc);
debug.addPossiblePrototypeExtension(func);
}
return buildResult(functionSymbol, namespc);
}
@@ -1318,11 +1304,8 @@ public class DecompileCallback {
Address addr;
int maxChars;
try {
addr = AddressXML.readXML(addrString, addrfactory);
maxChars = AddressXML.readXMLSize(addrString);
if (overlaySpace != null) {
addr = overlaySpace.getOverlayAddress(addr);
}
maxChars = readXMLSize(addrString);
addr = Varnode.readXMLAddress(addrString, addrfactory, funcEntry.getAddressSpace());
if (addr == Address.NO_ADDRESS) {
throw new PcodeXMLException("Address does not physically map");
}
@@ -47,7 +47,6 @@ public class DecompileDebug {
private Function func; // The function being decompiled
private Program program; // The program
private File debugFile; // The file to dump the XML document to
private Map<String, Object> specExtensions; // Local extensions to the compiler spec
private ArrayList<Namespace> dbscope; // Symbol query: scope
private ArrayList<String> database; // description of the symbol
private ArrayList<DataType> dtypes; // Data-types queried
@@ -109,17 +108,16 @@ public class DecompileDebug {
public DecompileDebug(File debugf) {
func = null;
debugFile = debugf;
specExtensions = new TreeMap<>();
dbscope = new ArrayList<>();
database = new ArrayList<>();
dtypes = new ArrayList<>();
context = new ArrayList<>();
cpool = new ArrayList<>();
byteset = new TreeSet<>();
contextchange = new TreeSet<>();
stringmap = new TreeMap<>();
flowoverride = new ArrayList<>();
inject = new ArrayList<>();
dbscope = new ArrayList<Namespace>();
database = new ArrayList<String>();
dtypes = new ArrayList<DataType>();
context = new ArrayList<String>();
cpool = new ArrayList<String>();
byteset = new TreeSet<ByteChunk>();
contextchange = new TreeSet<Address>();
stringmap = new TreeMap<Address, StringData>();
flowoverride = new ArrayList<String>();
inject = new ArrayList<String>();
contextRegister = null;
comments = null;
globalnamespace = null;
@@ -160,7 +158,6 @@ public class DecompileDebug {
buf.append(">\n");
debugStream.write(buf.toString().getBytes());
dumpImage(debugStream, pcodelanguage);
dumpExtensions(debugStream);
dumpCoretypes(debugStream);
debugStream.write("<save_state>\n".getBytes());
// dumpTypes(debugStream);
@@ -181,6 +178,7 @@ public class DecompileDebug {
debugStream.close();
}
catch (Exception e) {
// TODO Auto-generated catch block
Msg.error(this, "Unexpected Exception: " + e.getMessage(), e);
}
}
@@ -226,24 +224,24 @@ public class DecompileDebug {
lastreadonly = readval;
}
if (tagstarted && ((chunk.min != 0) || (lastspace != space) ||
(lastoffset != chunk.addr.getOffset()))) {
if (tagstarted &&
((chunk.min != 0) || (lastspace != space) || (lastoffset != chunk.addr.getOffset()))) {
buf.append("\n</bytechunk>\n");
tagstarted = false;
}
if (!tagstarted) {
buf.append("<bytechunk");
SpecXmlUtils.encodeStringAttribute(buf, "space",
space.getPhysicalSpace().getName());
SpecXmlUtils.encodeUnsignedIntegerAttribute(buf, "offset",
chunk.addr.getOffset() + chunk.min);
SpecXmlUtils.encodeStringAttribute(buf, "space", space.getPhysicalSpace().getName());
SpecXmlUtils.encodeUnsignedIntegerAttribute(buf, "offset", chunk.addr.getOffset() +
chunk.min);
if (lastreadonly) {
SpecXmlUtils.encodeBooleanAttribute(buf, "readonly", lastreadonly);
}
buf.append(">\n");
tagstarted = true;
}
for (int i = 0; i < chunk.min; ++i) {
for (int i = 0; i < chunk.min; ++i)
{
buf.append(" "); // pad the hex display to 16 bytes
}
for (int i = chunk.min; i < chunk.max; ++i) {
@@ -292,9 +290,9 @@ public class DecompileDebug {
StringBuilder buf = new StringBuilder();
buf.append("<stringmanage>\n");
for (Map.Entry<Address, StringData> entry : stringmap.entrySet()) {
buf.append("<string>\n");
AddressXML.buildXML(buf, entry.getKey());
buf.append("\n<bytes");
buf.append("<string>\n<addr");
Varnode.appendSpaceOffset(buf, entry.getKey());
buf.append("/>\n<bytes");
SpecXmlUtils.encodeBooleanAttribute(buf, "trunc", entry.getValue().isTruncated);
buf.append(">\n ");
int count = 0;
@@ -341,15 +339,12 @@ public class DecompileDebug {
new DataTypeDependencyOrderer(program.getDataTypeManager(), dtypes);
//First output all structures as zero size so to avoid any cyclic dependencies.
for (DataType dataType : TypeOrderer.getStructList()) {
debugStream.write(
(dtmanage.buildStructTypeZeroSizeOveride(dataType) + "\n").toString().getBytes());
debugStream.write((dtmanage.buildStructTypeZeroSizeOveride(dataType) + "\n").toString().getBytes());
}
//Next, use the dependency stack to output types.
for (DataType dataType : TypeOrderer.getDependencyList()) {
if (!(dataType instanceof BuiltIn)) {
debugStream.write(
(dtmanage.buildType(dataType, dataType.getLength()) + "\n").toString()
.getBytes());
debugStream.write((dtmanage.buildType(dataType, dataType.getLength()) + "\n").toString().getBytes());
}
}
debugStream.write("</typegrp>\n".getBytes());
@@ -370,7 +365,7 @@ public class DecompileDebug {
if (!(lang instanceof SleighLanguage)) {
return null;
}
ArrayList<ContextSymbol> res = new ArrayList<>();
ArrayList<ContextSymbol> res = new ArrayList<ContextSymbol>();
ghidra.app.plugin.processors.sleigh.symbol.Symbol[] list =
((SleighLanguage) lang).getSymbolTable().getSymbolList();
for (Symbol element : list) {
@@ -431,7 +426,8 @@ public class DecompileDebug {
break;
}
}
if (i == buf.length) {
if (i == buf.length)
{
continue; // If all data is identical, then changepoint is not necessary
}
}
@@ -443,7 +439,7 @@ public class DecompileDebug {
}
stringBuf.append("<context_pointset");
AddressXML.appendAttributes(stringBuf, addr);
Varnode.appendSpaceOffset(stringBuf, addr);
stringBuf.append(">\n");
for (ContextSymbol sym : ctxsymbols) {
int sbit = sym.getInternalLow();
@@ -470,7 +466,7 @@ public class DecompileDebug {
return;
}
debugStream.write("<constantpool>\n".getBytes());
for (String rec : cpool) {
for(String rec : cpool) {
debugStream.write(rec.getBytes());
}
debugStream.write("</constantpool>\n".getBytes());
@@ -496,8 +492,8 @@ public class DecompileDebug {
for (String element : flowoverride) {
debugStream.write(element.getBytes());
}
debugStream.write("</flowoverridelist>\n".getBytes());
debugStream.write("</flowoverridelist>\n".getBytes());
}
private void dumpInject(OutputStream debugStream) throws IOException {
@@ -512,11 +508,11 @@ public class DecompileDebug {
}
private ArrayList<Namespace> orderNamespaces() {
TreeMap<Long, Namespace> namespaceMap = new TreeMap<>();
TreeMap<Long, Namespace> namespaceMap = new TreeMap<Long, Namespace>();
for (Namespace namespace : dbscope) {
namespaceMap.put(namespace.getID(), namespace);
}
ArrayList<Namespace> res = new ArrayList<>();
ArrayList<Namespace> res = new ArrayList<Namespace>();
while (!namespaceMap.isEmpty()) {
Entry<Long, Namespace> entry = namespaceMap.firstEntry();
Long curKey = entry.getKey();
@@ -596,31 +592,6 @@ public class DecompileDebug {
debugStream.write("</db>\n".getBytes());
}
private void dumpExtensions(OutputStream debugStream) throws IOException {
if (specExtensions.isEmpty()) {
return;
}
PcodeInjectLibrary library = program.getCompilerSpec().getPcodeInjectLibrary();
debugStream.write("<specextensions>\n".getBytes());
for (Object obj : specExtensions.values()) {
if (obj instanceof PrototypeModel) {
PrototypeModel model = (PrototypeModel) obj;
StringBuilder buffer = new StringBuilder();
model.saveXml(buffer, library);
String modelString = buffer.toString();
debugStream.write(modelString.getBytes());
}
else if (obj instanceof InjectPayload) {
InjectPayload payload = (InjectPayload) obj;
StringBuilder buffer = new StringBuilder();
payload.saveXml(buffer);
String payloadString = buffer.toString();
debugStream.write(payloadString.getBytes());
}
}
debugStream.write("</specextensions>\n".getBytes());
}
private void dumpCoretypes(OutputStream debugStream) throws IOException {
debugStream.write(dtmanage.buildCoreTypes().getBytes());
}
@@ -695,9 +666,11 @@ public class DecompileDebug {
buf.append(" <labelsym");
SpecXmlUtils.xmlEscapeAttribute(buf, "name", name);
SpecXmlUtils.encodeUnsignedIntegerAttribute(buf, "id", id);
buf.append("/>\n ");
AddressXML.buildXML(buf, addr);
buf.append("\n <rangelist/>\n");
buf.append("/>\n");
buf.append(" <addr");
Varnode.appendSpaceOffset(buf, addr);
buf.append("/>\n");
buf.append(" <rangelist/>\n");
buf.append("</mapsym>\n");
getMapped(namespace, buf.toString());
}
@@ -738,7 +711,7 @@ public class DecompileDebug {
context.add(doc);
}
public void getCPoolRef(String rec, long[] refs) {
public void getCPoolRef(String rec,long[] refs) {
StringBuilder buf = new StringBuilder();
buf.append("<ref");
SpecXmlUtils.encodeUnsignedIntegerAttribute(buf, "a", refs[0]);
@@ -760,7 +733,7 @@ public class DecompileDebug {
getMapped(spc, buffer.toString());
}
public void addFlowOverride(Address addr, FlowOverride fo) {
public void addFlowOverride(Address addr,FlowOverride fo) {
StringBuilder buf = new StringBuilder();
buf.append("<flow type=\"");
if (fo == FlowOverride.BRANCH) {
@@ -778,44 +751,25 @@ public class DecompileDebug {
else {
buf.append("none");
}
buf.append("\">");
AddressXML.buildXML(buf, func.getEntryPoint());
AddressXML.buildXML(buf, addr);
buf.append("</flow>\n");
buf.append("\"><addr");
Varnode.appendSpaceOffset(buf,func.getEntryPoint());
buf.append("/><addr");
Varnode.appendSpaceOffset(buf, addr);
buf.append("/></flow>\n");
flowoverride.add(buf.toString());
}
public void addInject(Address addr, String name, int injectType, String payload) {
public void addInject(Address addr,String name,int injectType,String payload) {
StringBuilder buf = new StringBuilder();
buf.append("<inject name=\"");
buf.append(name);
buf.append('"');
SpecXmlUtils.encodeSignedIntegerAttribute(buf, "type", injectType);
buf.append(">\n ");
AddressXML.buildXML(buf, addr);
buf.append("\n <payload><![CDATA[\n");
buf.append(">\n <addr");
Varnode.appendSpaceOffset(buf, addr);
buf.append("/>\n <payload><![CDATA[\n");
buf.append(payload);
buf.append("\n]]></payload>\n</inject>\n");
inject.add(buf.toString());
PcodeInjectLibrary library = program.getCompilerSpec().getPcodeInjectLibrary();
if (library.hasProgramPayload(name, injectType)) {
InjectPayload programPayload = library.getPayload(injectType, name);
String title =
(injectType == InjectPayload.CALLFIXUP_TYPE) ? "callfixup_" : "callotherfixup_";
title = title + name;
specExtensions.put(title, programPayload);
}
}
public void addPossiblePrototypeExtension(Function testFunc) {
PrototypeModel model = testFunc.getCallingConvention();
if (model == null) {
return;
}
if (model.isProgramExtension()) {
String title = "prototype_" + model.getName();
specExtensions.put(title, model);
}
}
}
@@ -27,9 +27,7 @@ import ghidra.framework.options.Options;
import ghidra.framework.options.ToolOptions;
import ghidra.framework.plugintool.Plugin;
import ghidra.framework.plugintool.PluginTool;
import ghidra.program.database.ProgramCompilerSpec;
import ghidra.program.model.lang.*;
import ghidra.program.model.lang.CompilerSpec.EvaluationModelType;
import ghidra.program.model.listing.Program;
import ghidra.util.HelpLocation;
import ghidra.util.SystemUtilities;
@@ -406,7 +404,7 @@ public class DecompileOptions {
codeViewerBackgroundColor = CODE_VIEWER_BACKGROUND_COLOR;
defaultFont = DEFAULT_FONT;
displayLineNumbers = LINE_NUMBER_DEF;
displayLanguage = ProgramCompilerSpec.DECOMPILER_OUTPUT_DEF;
displayLanguage = BasicCompilerSpec.DECOMPILER_OUTPUT_DEF;
protoEvalModel = "default";
decompileTimeoutSeconds = SUGGESTED_DECOMPILE_TIMEOUT_SECS;
payloadLimitMBytes = SUGGESTED_MAX_PAYLOAD_BYTES;
@@ -505,21 +503,21 @@ public class DecompileOptions {
*/
public void grabFromProgram(Program program) {
// Default values, even if there is no program
displayLanguage = ProgramCompilerSpec.DECOMPILER_OUTPUT_DEF;
displayLanguage = BasicCompilerSpec.DECOMPILER_OUTPUT_DEF;
protoEvalModel = "default";
if (program == null) {
return;
}
CompilerSpec cspec = program.getCompilerSpec();
PrototypeModel model = cspec.getPrototypeEvaluationModel(EvaluationModelType.EVAL_CURRENT);
PrototypeModel model = (PrototypeModel) cspec.getPrototypeEvaluationModel(program);
if (model != null) {
String modelname = model.getName();
if (modelname != null) {
protoEvalModel = modelname;
}
}
displayLanguage = cspec.getDecompilerOutputLanguage();
displayLanguage = cspec.getDecompilerOutputLanguage(program);
}
public String getProtoEvalModel() {
@@ -4,15 +4,19 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Created on Jun 3, 2005
*
*/
package ghidra.app.decompiler;
import java.io.*;
@@ -29,7 +29,6 @@ import ghidra.framework.model.DomainFile;
import ghidra.framework.options.SaveState;
import ghidra.framework.plugintool.*;
import ghidra.framework.plugintool.util.PluginStatus;
import ghidra.program.database.SpecExtension;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.*;
import ghidra.program.util.ProgramLocation;
@@ -232,9 +231,6 @@ public class DecompilePlugin extends Plugin {
if (event instanceof ProgramActivatedPluginEvent) {
currentProgram = ((ProgramActivatedPluginEvent) event).getActiveProgram();
connectedProvider.doSetProgram(currentProgram);
if (currentProgram != null) {
SpecExtension.registerOptions(currentProgram);
}
}
else if (event instanceof ProgramLocationPluginEvent) {
ProgramLocation location = ((ProgramLocationPluginEvent) event).getLocation();
@@ -36,11 +36,11 @@ import ghidra.app.plugin.core.decompile.actions.*;
import ghidra.app.services.*;
import ghidra.app.util.HelpTopics;
import ghidra.app.util.HighlightProvider;
import ghidra.framework.model.*;
import ghidra.framework.model.DomainObjectChangedEvent;
import ghidra.framework.model.DomainObjectListener;
import ghidra.framework.options.*;
import ghidra.framework.plugintool.NavigatableComponentProviderAdapter;
import ghidra.framework.plugintool.util.ServiceListener;
import ghidra.program.database.SpecExtension;
import ghidra.program.model.address.*;
import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.Program;
@@ -307,33 +307,17 @@ public class DecompilerProvider extends NavigatableComponentProviderAdapter
@Override
public void domainObjectChanged(DomainObjectChangedEvent ev) {
// Check for events that signal that a decompiler process' data is stale
// and if so force a new process to be spawned
if (ev.containsEvent(ChangeManager.DOCR_MEMORY_BLOCK_ADDED) ||
ev.containsEvent(ChangeManager.DOCR_MEMORY_BLOCK_REMOVED) ||
ev.containsEvent(DomainObject.DO_OBJECT_RESTORED)) {
controller.resetDecompiler();
}
else if (ev.containsEvent(DomainObject.DO_PROPERTY_CHANGED)) {
Iterator<DomainObjectChangeRecord> iter = ev.iterator();
while (iter.hasNext()) {
DomainObjectChangeRecord record = iter.next();
if (record.getEventType() == DomainObject.DO_PROPERTY_CHANGED) {
if (record.getOldValue() instanceof String) {
String value = (String) record.getOldValue();
if (value.startsWith(SpecExtension.SPEC_EXTENSION)) {
controller.resetDecompiler();
break;
}
}
}
}
if (!isVisible()) {
return;
}
// Trigger a redecompile an any program change if the window is active
if (isVisible()) {
redecompileUpdater.update();
if (ev.containsEvent(ChangeManager.DOCR_MEMORY_BLOCK_ADDED) ||
ev.containsEvent(ChangeManager.DOCR_MEMORY_BLOCK_REMOVED)) {
controller.resetDecompiler();
}
redecompileUpdater.update();
}
private void doRefresh() {
@@ -26,7 +26,6 @@ import ghidra.app.decompiler.parallel.*;
import ghidra.app.plugin.core.analysis.validator.PostAnalysisValidator;
import ghidra.program.model.address.Address;
import ghidra.program.model.lang.CompilerSpec;
import ghidra.program.model.lang.CompilerSpec.EvaluationModelType;
import ghidra.program.model.lang.PrototypeModel;
import ghidra.program.model.listing.*;
import ghidra.util.Msg;
@@ -47,7 +46,7 @@ public class DecompilerValidator extends PostAnalysisValidator {
List<Function> functions = filterFunctions(program, iter, monitor);
DecompilerCallback<String> callback =
new DecompilerCallback<>(program, new DecompilerValidatorConfigurer()) {
new DecompilerCallback<String>(program, new DecompilerValidatorConfigurer()) {
@Override
public String process(DecompileResults results, TaskMonitor m) throws Exception {
@@ -148,8 +147,7 @@ public class DecompilerValidator extends PostAnalysisValidator {
private DecompileOptions getDecompilerOptions() {
try {
CompilerSpec spec = program.getCompilerSpec();
PrototypeModel model =
spec.getPrototypeEvaluationModel(EvaluationModelType.EVAL_CURRENT);
PrototypeModel model = (PrototypeModel) spec.getPrototypeEvaluationModel(program);
options.setProtoEvalModel(model.getName());
}
catch (Exception e) {
@@ -29,7 +29,6 @@ import docking.widgets.fieldpanel.support.FieldLocation;
import ghidra.app.decompiler.ClangToken;
import ghidra.app.decompiler.component.ClangTextField;
import ghidra.app.decompiler.component.DecompilerPanel;
import ghidra.program.model.pcode.HighFunction;
import ghidra.test.AbstractProgramBasedTest;
public abstract class AbstractDecompilerTest extends AbstractProgramBasedTest {
@@ -172,34 +171,4 @@ public abstract class AbstractDecompilerTest extends AbstractProgramBasedTest {
assertEquals(tokenText, text);
}
}
protected ClangTextField getLineStarting(String val) {
DecompilerPanel panel = provider.getDecompilerPanel();
List<Field> fields = panel.getFields();
for (Field field : fields) {
ClangTextField textField = (ClangTextField) field;
String text = textField.getText().trim();
if (text.startsWith(val)) {
return textField;
}
}
return null;
}
protected ClangTextField getLineContaining(String val) {
DecompilerPanel panel = provider.getDecompilerPanel();
List<Field> fields = panel.getFields();
for (Field field : fields) {
ClangTextField textField = (ClangTextField) field;
String text = textField.getText();
if (text.contains(val)) {
return textField;
}
}
return null;
}
protected HighFunction getHighFunction() {
return provider.getController().getHighFunction();
}
}
@@ -17,8 +17,11 @@ package ghidra.app.plugin.core.decompile;
import static org.junit.Assert.*;
import java.util.List;
import org.junit.Test;
import docking.widgets.fieldpanel.field.Field;
import docking.widgets.fieldpanel.support.FieldLocation;
import ghidra.app.cmd.equate.SetEquateCmd;
import ghidra.app.cmd.function.CreateFunctionCmd;
@@ -27,6 +30,7 @@ import ghidra.app.cmd.label.RenameLabelCmd;
import ghidra.app.decompiler.ClangToken;
import ghidra.app.decompiler.ClangVariableToken;
import ghidra.app.decompiler.component.ClangTextField;
import ghidra.app.decompiler.component.DecompilerPanel;
import ghidra.app.plugin.core.decompile.actions.IsolateVariableTask;
import ghidra.app.plugin.core.decompile.actions.RenameVariableTask;
import ghidra.framework.options.Options;
@@ -45,6 +49,36 @@ public class HighSymbolTest extends AbstractDecompilerTest {
return "Winmine__XP.exe.gzf";
}
protected ClangTextField getLineStarting(String val) {
DecompilerPanel panel = provider.getDecompilerPanel();
List<Field> fields = panel.getFields();
for (Field field : fields) {
ClangTextField textField = (ClangTextField) field;
String text = textField.getText().trim();
if (text.startsWith(val)) {
return textField;
}
}
return null;
}
protected ClangTextField getLineContaining(String val) {
DecompilerPanel panel = provider.getDecompilerPanel();
List<Field> fields = panel.getFields();
for (Field field : fields) {
ClangTextField textField = (ClangTextField) field;
String text = textField.getText();
if (text.contains(val)) {
return textField;
}
}
return null;
}
protected HighFunction getHighFunction() {
return provider.getController().getHighFunction();
}
private void renameGlobalVariable(HighSymbol highSymbol, ClangToken tokenAtCursor,
String newName) {
Address addr = highSymbol.getStorage().getMinAddress();
@@ -80,7 +114,6 @@ public class HighSymbolTest extends AbstractDecompilerTest {
options.setBoolean("Stack", false);
});
}
private void renameVariable(HighSymbol highSymbol, ClangToken tokenAtCursor, String newName) {
RenameVariableTask rename =
new RenameVariableTask(provider.getTool(), highSymbol.getProgram(),
@@ -1,259 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.plugin.core.decompile;
import static org.junit.Assert.*;
import java.util.List;
import org.junit.Test;
import org.xml.sax.SAXException;
import ghidra.app.decompiler.component.ClangTextField;
import ghidra.app.plugin.processors.sleigh.SleighException;
import ghidra.framework.options.Options;
import ghidra.framework.store.LockException;
import ghidra.program.database.ProgramCompilerSpec;
import ghidra.program.database.SpecExtension;
import ghidra.program.model.address.Address;
import ghidra.program.model.lang.*;
import ghidra.program.model.lang.CompilerSpec.EvaluationModelType;
import ghidra.program.model.listing.Function;
import ghidra.program.model.symbol.SourceType;
import ghidra.util.exception.CancelledException;
import ghidra.util.exception.InvalidInputException;
import ghidra.util.task.TaskMonitor;
import ghidra.xml.XmlParseException;
public class SpecExtensionTest extends AbstractDecompilerTest {
@Override
protected String getProgramName() {
return "Winmine__XP.exe.gzf";
}
@Test
public void test_BadCallotherTarget() {
String myfixup = "<callotherfixup targetop=\"unknownop\">\n" + " <pcode>\n" +
" <input name=\"fcx\"/>\n" + " <body><![CDATA[\n" + " EAX = fcx + 2;\n" +
" ]]></body>\n" + " </pcode>\n" + "</callotherfixup>\n";
String errMessage = null;
try {
SpecExtension specExtension = new SpecExtension(program);
specExtension.addReplaceCompilerSpecExtension(myfixup, TaskMonitor.DUMMY);
}
catch (SleighException | XmlParseException | SAXException | LockException ex) {
errMessage = ex.getMessage();
}
assertTrue(errMessage.contains("CALLOTHER_FIXUP target does not exist"));
}
@Test
public void test_BadExtension() {
// Document with a p-code compile error
String myfixup = "<callfixup name=\"mynewthing\">\n" + " <target name=\"targ1\"/>\n" +
" <pcode>\n" + " <body><![CDATA[\n" + " *ESP = 1000:4;\n" +
" ESP = blahhh - 4;\n" + " ]]></body>\n" + " </pcode>\n" + "</callfixup>\n";
String errMessage = null;
SpecExtension specExtension = new SpecExtension(program);
try {
specExtension.addReplaceCompilerSpecExtension(myfixup, TaskMonitor.DUMMY);
}
catch (SleighException | XmlParseException | SAXException | LockException ex) {
errMessage = ex.getMessage();
}
assertTrue(errMessage.contains("halting compilation"));
// Document with an XML parsing problem
myfixup = "<callfixup name=\"mynewthing\"> </badendtag>";
errMessage = null;
String subError = null;
try {
specExtension.testExtensionDocument(myfixup);
}
catch (Exception e) {
errMessage = e.getMessage();
subError = e.getCause().getMessage();
}
assertTrue(errMessage.contains("Invalid compiler specification"));
assertTrue(subError.contains("must be terminated by the matching"));
// Document that does not validate against the grammar
myfixup = "<callfixup> <pcode> <body><![CDATA[ESP = 1000;\n]]></body></pcode></callfixup>";
errMessage = null;
try {
specExtension.testExtensionDocument(myfixup);
}
catch (Exception e) {
errMessage = e.getMessage();
}
assertTrue(errMessage.contains("Could not find attribute: name"));
}
@Test
public void test_ExtensionNameCollision() {
// Legal document that would overwrite a core callfixup
String myfixup =
"<callfixup name=\"alloca_probe\"><pcode><body>ESP = ESP - 4;</body></pcode></callfixup>";
String errMessage = null;
SpecExtension specExtension = new SpecExtension(program);
try {
specExtension.addReplaceCompilerSpecExtension(myfixup, TaskMonitor.DUMMY);
}
catch (SleighException | XmlParseException | SAXException | LockException ex) {
errMessage = ex.getMessage();
}
assertTrue(errMessage.contains("Extension cannot replace"));
}
@Test
public void test_PrototypeExtension() {
decompile("100272e");
ClangTextField line = getLineContaining("FUN_010026a7(pHVar1);");
assertNotNull(line);
CompilerSpec cspec = program.getCompilerSpec();
PrototypeModel defaultModel = cspec.getDefaultCallingConvention();
StringBuilder buffer = new StringBuilder();
defaultModel.saveXml(buffer, cspec.getPcodeInjectLibrary());
String defaultString = buffer.toString();
// Replace the output register EAX with ECX
defaultString = defaultString.replace("<addr space=\"register\" offset=\"0x0\"/>",
"<addr space=\"register\" offset=\"4\"/>");
// Change the name
defaultString = defaultString.replace("name=\"__stdcall\"", "name=\"myproto\"");
SpecExtension specExtension = new SpecExtension(program);
int id1 = program.startTransaction("Test prototype install");
try {
specExtension.addReplaceCompilerSpecExtension(defaultString, TaskMonitor.DUMMY);
}
catch (LockException | SleighException | SAXException | XmlParseException ex) {
throw new AssertionError("Unexpected exception: " + ex.getMessage());
}
program.endTransaction(id1, true);
PrototypeModel myproto = cspec.getCallingConvention("myproto");
assertNotNull(myproto);
int id = program.startTransaction("test extension install");
Address addr = program.getAddressFactory().getDefaultAddressSpace().getAddress(0x100112c);
Function func = program.getFunctionManager().getReferencedFunction(addr);
boolean changeWorks = true;
try {
func.setCallingConvention("myproto");
}
catch (InvalidInputException e) {
changeWorks = false;
}
program.endTransaction(id, true);
assertTrue(changeWorks);
decompile("100272e");
// Look for the affect of ECX being the output register
line = getLineContaining("FUN_010026a7(extraout_EAX);");
assertNotNull(line);
int id3 = program.startTransaction("Change eval model");
Options options = program.getOptions(ProgramCompilerSpec.DECOMPILER_PROPERTY_LIST_NAME);
options.setString(ProgramCompilerSpec.EVALUATION_MODEL_PROPERTY_NAME, "myproto");
program.endTransaction(id3, true);
PrototypeModel evalModel =
program.getCompilerSpec().getPrototypeEvaluationModel(EvaluationModelType.EVAL_CURRENT);
ParamList.WithSlotRec res = new ParamList.WithSlotRec();
Address ecxAddr = program.getAddressFactory().getRegisterSpace().getAddress(4);
boolean outExists = evalModel.possibleOutputParamWithSlot(ecxAddr, 4, res);
assertTrue(outExists);
int id2 = program.startTransaction("test extension removal");
try {
specExtension.removeCompilerSpecExtension("prototype_myproto", TaskMonitor.DUMMY);
}
catch (LockException | CancelledException ex) {
throw new AssertionError("Unexpected exception: " + ex.getMessage());
}
program.endTransaction(id2, true);
myproto = cspec.getCallingConvention("myproto");
assertNull(myproto);
assertFalse(func.getCallingConventionName().equals("myproto"));
evalModel =
program.getCompilerSpec().getPrototypeEvaluationModel(EvaluationModelType.EVAL_CURRENT);
assertEquals(evalModel.getName(), "__stdcall");
}
@Test
public void test_CallFixupExtension() {
String myfixup = "<callfixup name=\"mynewthing\">\n" + " <target name=\"targ1\"/>\n" +
" <pcode>\n" + " <body><![CDATA[\n" + " *ESP = 1000:4;\n" +
" ESP = ESP - 4;\n" + " *:4 ESP = inst_next;\n" + " ]]></body>\n" +
" </pcode>\n" + "</callfixup>\n";
SpecExtension specExtension = new SpecExtension(program);
int id1 = program.startTransaction("test extension install");
try {
specExtension.addReplaceCompilerSpecExtension(myfixup, TaskMonitor.DUMMY);
}
catch (LockException | SleighException | SAXException | XmlParseException ex) {
throw new AssertionError("Unexpected exception: " + ex.getMessage());
}
program.endTransaction(id1, true);
PcodeInjectLibrary library = program.getCompilerSpec().getPcodeInjectLibrary();
InjectPayloadSleigh[] programPayloads = library.getProgramPayloads();
assertEquals(programPayloads.length, 1);
InjectPayload payload = programPayloads[0];
assertTrue(programPayloads[0] instanceof InjectPayloadCallfixup);
InjectPayloadCallfixup callfixup = (InjectPayloadCallfixup) payload;
List<String> targets = callfixup.getTargets();
assertEquals(targets.size(), 1);
assertEquals(targets.get(0), "targ1");
assertEquals(payload.getName(), "mynewthing");
assertTrue(payload.isFallThru());
assertFalse(payload.isIncidentalCopy());
int id = program.startTransaction("test extensions");
Address firstAddr =
program.getAddressFactory().getDefaultAddressSpace().getAddress(0x1002607);
Function func1 = program.getFunctionManager().getFunctionAt(firstAddr);
func1.setCallFixup("mynewthing");
Address secondAddr =
program.getAddressFactory().getDefaultAddressSpace().getAddress(0x10038d7);
Function func = program.getFunctionManager().getFunctionAt(secondAddr);
func.setSignatureSource(SourceType.DEFAULT);
program.endTransaction(id, true);
decompile("100263c");
ClangTextField line = getLineContaining("injection: mynewthing");
assertNotNull(line);
// injection causes remaining call to look like it takes 1000 as a parameter
line = getLineStarting("FUN_010038d7(1000);");
assertNotNull(line);
// Remove the fixup extension
int id2 = program.startTransaction("test extension removal");
try {
specExtension.removeCompilerSpecExtension("callfixup_mynewthing", TaskMonitor.DUMMY);
}
catch (LockException | CancelledException ex) {
throw new AssertionError("Unexpected exception: " + ex.getMessage());
}
program.endTransaction(id2, true);
programPayloads = library.getProgramPayloads();
assertNull(programPayloads);
decompile("100263c");
line = getLineStarting("FUN_01002607();");
assertNotNull(line);
line = getLineStarting("FUN_010038d7();");
assertNotNull(line);
}
}
@@ -28,12 +28,10 @@ import ghidra.app.util.importer.MessageLog;
import ghidra.file.analyzers.FileFormatAnalyzer;
import ghidra.file.formats.android.dex.format.*;
import ghidra.file.formats.android.dex.util.DexUtil;
import ghidra.program.database.ProgramCompilerSpec;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSetView;
import ghidra.program.model.data.*;
import ghidra.program.model.lang.Language;
import ghidra.program.model.lang.Register;
import ghidra.program.model.lang.*;
import ghidra.program.model.listing.*;
import ghidra.program.model.listing.Function.FunctionUpdateType;
import ghidra.program.model.mem.Memory;
@@ -67,7 +65,7 @@ public class DexHeaderFormatAnalyzer extends FileFormatAnalyzer {
createInitialFragments(program, header, monitor);
ProgramCompilerSpec.enableJavaLanguageDecompilation(program);
BasicCompilerSpec.enableJavaLanguageDecompilation(program);
createNamespaces(program, header, monitor, log);
processMap(program, header, monitor, log);
processStrings(program, header, monitor, log);
@@ -174,9 +172,11 @@ public class DexHeaderFormatAnalyzer extends FileFormatAnalyzer {
return;
}
for (EncodedMethod encodedMethod : methods) {
for (int i = 0; i < methods.size(); ++i) {
monitor.checkCanceled();
EncodedMethod encodedMethod = methods.get(i);
MethodIDItem methodID = header.getMethods().get(encodedMethod.getMethodIndex());
String methodName = DexUtil.convertToString(header, methodID.getNameIndex());
@@ -213,8 +213,8 @@ public class DexHeaderFormatAnalyzer extends FileFormatAnalyzer {
Namespace classNameSpace, MessageLog log) {
program.getSymbolTable().addExternalEntryPoint(methodAddress);
try {
return program.getSymbolTable()
.createLabel(methodAddress, methodName, classNameSpace, SourceType.ANALYSIS);
return program.getSymbolTable().createLabel(methodAddress, methodName, classNameSpace,
SourceType.ANALYSIS);
}
catch (InvalidInputException e) {
log.appendException(e);
@@ -240,8 +240,8 @@ public class DexHeaderFormatAnalyzer extends FileFormatAnalyzer {
commentBuilder.append("Method Debug Info Offset: 0x" +
Integer.toHexString(codeItem.getDebugInfoOffset()) + "\n");
}
commentBuilder
.append("Method ID Offset: 0x" + Long.toHexString(methodID.getFileOffset()) + "\n");
commentBuilder.append(
"Method ID Offset: 0x" + Long.toHexString(methodID.getFileOffset()) + "\n");
setPlateComment(program, methodAddress, commentBuilder.toString());
}
@@ -522,9 +522,11 @@ public class DexHeaderFormatAnalyzer extends FileFormatAnalyzer {
private void processEncodedMethods(Program program, DexHeader header, ClassDefItem item,
List<EncodedMethod> methods, TaskMonitor monitor) throws Exception {
for (EncodedMethod method : methods) {
for (int i = 0; i < methods.size(); ++i) {
monitor.checkCanceled();
EncodedMethod method = methods.get(i);
MethodIDItem methodID = header.getMethods().get(method.getMethodIndex());
StringBuilder builder = new StringBuilder();
@@ -660,8 +662,7 @@ public class DexHeaderFormatAnalyzer extends FileFormatAnalyzer {
methodAddress.add(setItemDataType.getLength()));
processAnnotationSetItem(program, setItem, monitor, log);
}
for (ParameterAnnotation parameter : annotationsDirectoryItem
.getParameterAnnotations()) {
for (ParameterAnnotation parameter : annotationsDirectoryItem.getParameterAnnotations()) {
monitor.checkCanceled();
Address parameterAddress = toAddr(program, parameter.getAnnotationsOffset());
AnnotationSetReferenceList annotationSetReferenceList =
@@ -766,9 +767,9 @@ public class DexHeaderFormatAnalyzer extends FileFormatAnalyzer {
classNameSpace, log);
if (methodSymbol != null) {
String externalName = methodSymbol.getName(true);
program.getReferenceManager()
.addExternalReference(methodIndexAddress, "EXTERNAL.dex",
externalName, null, SourceType.ANALYSIS, 0, RefType.DATA);
program.getReferenceManager().addExternalReference(methodIndexAddress,
"EXTERNAL.dex", externalName, null, SourceType.ANALYSIS, 0,
RefType.DATA);
}
}
}
@@ -481,8 +481,7 @@ public abstract class DomainObjectAdapterDB extends DomainObjectAdapter
*/
protected boolean propertyChanged(String propertyName, Object oldValue, Object newValue) {
setChanged(true);
fireEvent(
new DomainObjectChangeRecord(DomainObject.DO_PROPERTY_CHANGED, propertyName, newValue));
fireEvent(new DomainObjectChangeRecord(DomainObject.DO_PROPERTY_CHANGED, name, name));
return true;
}
@@ -157,8 +157,6 @@ class OptionsDB extends AbstractOptions {
public synchronized void removeOption(String propertyName) {
super.removeOption(propertyName);
removePropertyFromDB(propertyName);
// NOTE: AbstractOptions does not provide removal notification
notifyOptionChanged(propertyName, null, null);
}
private void removePropertyFromDB(String propertyName) {
@@ -333,7 +331,7 @@ class OptionsDB extends AbstractOptions {
@Override
protected boolean notifyOptionChanged(String optionName, Object oldValue, Object newValue) {
return domainObj.propertyChanged(optionName, oldValue, newValue);
return domainObj.propertyChanged(name, oldValue, newValue);
}
}
@@ -122,8 +122,7 @@ public class SleighLanguage implements Language {
throws SAXException, IOException, UnknownInstructionException {
this.defaultSymbols = new ArrayList<>();
this.compilerSpecDescriptions = new LinkedHashMap<>();
for (CompilerSpecDescription compilerSpecDescription : langDescription
.getCompatibleCompilerSpecDescriptions()) {
for (CompilerSpecDescription compilerSpecDescription : langDescription.getCompatibleCompilerSpecDescriptions()) {
this.compilerSpecDescriptions.put(compilerSpecDescription.getCompilerSpecID(),
(SleighCompilerSpecDescription) compilerSpecDescription);
}
@@ -479,9 +478,8 @@ public class SleighLanguage implements Language {
String[] args;
if (sleighArgsFile != null && sleighArgsFile.isFile()) {
String baseDir = Application.getInstallationDirectory()
.getAbsolutePath()
.replace(File.separatorChar, '/');
String baseDir = Application.getInstallationDirectory().getAbsolutePath().replace(
File.separatorChar, '/');
if (!baseDir.endsWith("/")) {
baseDir += "/";
}
@@ -628,14 +626,63 @@ public class SleighLanguage implements Language {
return new Pair<>(addrspace.getAddress(first), addrspace.getAddress(last));
}
private void read(XmlPullParser parser) throws XmlParseException {
private void parseJumpAssist(XmlElement el, XmlPullParser parser) {
String name = el.getAttribute("name");
String source = "pspec: " + getLanguageID().getIdAsString();
while (parser.peek().isStart()) {
String subName;
XmlElement subel = parser.peek();
if (subel.getName().charAt(0) == 'c') {
subName = name + "_index2case";
}
else if (subel.getName().charAt(0) == 'a') {
subName = name + "_index2addr";
}
else if (subel.getName().charAt(0) == 's') {
subName = name + "_calcsize";
}
else {
subName = name + "_defaultaddr";
}
InjectPayloadSleigh payload =
new InjectPayloadSleigh(subName, InjectPayload.EXECUTABLEPCODE_TYPE, source);
payload.restoreXml(parser);
addAdditionInject(payload);
}
}
public InjectPayloadSleigh parseSegmentOp(XmlElement el, XmlPullParser parser) {
String name = el.getAttribute("userop");
if (name == null) {
name = "segment";
}
name = name + "_pcode";
String source = "pspec: " + getLanguageID().getIdAsString();
InjectPayloadSleigh payload = null;
if (parser.peek().isStart()) {
if (parser.peek().getName().equals("pcode")) {
payload = new InjectPayloadSleigh(name, InjectPayload.EXECUTABLEPCODE_TYPE, source);
payload.restoreXml(parser);
}
}
while (parser.peek().isStart()) {
parser.discardSubTree();
}
if (payload == null) {
throw new SleighException("Missing <pcode> child for <segmentop> tag");
}
return payload;
}
private void read(XmlPullParser parser) {
Set<String> registerDataSet = new HashSet<>();
XmlElement el = parser.start("processor_spec");
while (parser.peek().isStart()) {
String elName = parser.peek().getName();
if (elName.equals("properties")) {
XmlElement subel = parser.start();
XmlElement element = parser.start("processor_spec");
while (!parser.peek().isEnd()) {
element = parser.start("properties", "segmented_address", "segmentop", "programcounter",
"data_space", "inferptrbounds", "context_data", "volatile", "jumpassist",
"incidentalcopy", "register_data", "default_symbols", "default_memory_blocks");
if (element.getName().equals("properties")) {
while (!parser.peek().isEnd()) {
XmlElement next = parser.start("property");
String key = next.getAttribute("key");
@@ -643,17 +690,13 @@ public class SleighLanguage implements Language {
properties.put(key, value);
parser.end(next);
}
parser.end(subel);
}
else if (elName.equals("programcounter")) {
XmlElement subel = parser.start();
setProgramCounter(subel.getAttribute("register"));
parser.end(subel);
else if (element.getName().equals("programcounter")) {
setProgramCounter(element.getAttribute("register"));
}
else if (elName.equals("data_space")) {
XmlElement subel = parser.start();
setDefaultDataSpace(subel.getAttribute("space"));
String overrideString = subel.getAttribute("ptr_wordsize");
else if (element.getName().equals("data_space")) {
setDefaultDataSpace(element.getAttribute("space"));
String overrideString = element.getAttribute("ptr_wordsize");
if (overrideString != null) {
int val = SpecXmlUtils.decodeInt(overrideString);
if (val <= 0 || val >= 32) {
@@ -661,10 +704,8 @@ public class SleighLanguage implements Language {
}
defaultPointerWordSize = val;
}
parser.end(subel);
}
else if (elName.equals("context_data")) {
XmlElement subel = parser.start();
else if (element.getName().equals("context_data")) {
while (!parser.peek().isEnd()) {
XmlElement next = parser.start();
boolean isContext = next.getName().equals("context_set");
@@ -703,10 +744,8 @@ public class SleighLanguage implements Language {
// skip the end tag
parser.end(next);
}
parser.end(subel);
}
else if (elName.equals("volatile")) {
XmlElement subel = parser.start();
else if (element.getName().equals("volatile")) {
while (!parser.peek().getName().equals("volatile")) {
XmlElement next = parser.start();
if (next.getName().equals("register")) {
@@ -720,21 +759,11 @@ public class SleighLanguage implements Language {
// skip the end tag
parser.end(next);
}
parser.end(subel);
}
else if (elName.equals("jumpassist")) {
XmlElement subel = parser.start();
String source = "pspec: " + getLanguageID().getIdAsString();
String name = subel.getAttribute("name");
while (parser.peek().isStart()) {
InjectPayloadSleigh payload = new InjectPayloadJumpAssist(name, source);
payload.restoreXml(parser, this);
addAdditionInject(payload);
}
parser.end(subel);
else if (element.getName().equals("jumpassist")) {
parseJumpAssist(element, parser);
}
else if (elName.equals("register_data")) {
XmlElement subel = parser.start();
else if (element.getName().equals("register_data")) {
while (parser.peek().getName().equals("register")) {
XmlElement reg = parser.start();
String registerName = reg.getAttribute("name");
@@ -777,10 +806,8 @@ public class SleighLanguage implements Language {
// skip the end tag
parser.end(reg);
}
parser.end(subel);
}
else if (elName.equals("default_symbols")) {
XmlElement subel = parser.start();
else if (element.getName().equals("default_symbols")) {
while (parser.peek().getName().equals("symbol")) {
XmlElement symbol = parser.start();
String labelName = symbol.getAttribute("name");
@@ -801,10 +828,8 @@ public class SleighLanguage implements Language {
// skip the end tag
parser.end(symbol);
}
parser.end(subel);
}
else if (elName.equals("default_memory_blocks")) {
XmlElement subel = parser.start();
else if (element.getName().equals("default_memory_blocks")) {
List<MemoryBlockDefinition> list = new ArrayList<>();
while (parser.peek().getName().equals("memory_block")) {
XmlElement mblock = parser.start();
@@ -812,39 +837,27 @@ public class SleighLanguage implements Language {
// skip the end tag
parser.end(mblock);
}
parser.end(subel);
defaultMemoryBlocks = new MemoryBlockDefinition[list.size()];
list.toArray(defaultMemoryBlocks);
}
else if (elName.equals("incidentalcopy")) {
XmlElement subel = parser.start();
else if (element.getName().equals("incidentalcopy")) {
while (parser.peek().isStart()) {
parser.discardSubTree();
}
parser.end(subel);
}
else if (elName.equals("inferptrbounds")) {
XmlElement subel = parser.start();
else if (element.getName().equals("inferptrbounds")) {
while (parser.peek().isStart()) {
parser.discardSubTree();
}
parser.end(subel);
}
else if (elName.equals("segmentop")) {
String source = "pspec: " + getLanguageID().getIdAsString();
InjectPayloadSleigh payload = new InjectPayloadSegment(source);
payload.restoreXml(parser, this);
else if (element.getName().equals("segmentop")) {
InjectPayloadSleigh payload = parseSegmentOp(element, parser);
addAdditionInject(payload);
}
else if (elName.equals("segmented_address")) {
XmlElement subel = parser.start();
parser.end(subel);
}
else {
throw new XmlParseException("Unknown pspec tag: " + elName);
}
// get rid of the end tag of whatever we started with at the top of the while
parser.end(element);
}
parser.end(el);
parser.dispose();
}
private void readRemainingSpecification() throws SAXException, IOException {
@@ -853,9 +866,6 @@ public class SleighLanguage implements Language {
try {
read(parser);
}
catch (XmlParseException e) {
Msg.error(this, e.getMessage());
}
finally {
parser.dispose();
}
@@ -898,8 +908,9 @@ public class SleighLanguage implements Language {
if (isBigEndian ^ description.getEndian().isBigEndian()) {
if (description.getInstructionEndian().isBigEndian() == description.getEndian()
.isBigEndian()) {
throw new SleighException(".ldefs says " + getLanguageID() + " is " +
description.getEndian() + " but .sla says " + el.getAttribute("bigendian"));
throw new SleighException(
".ldefs says " + getLanguageID() + " is " + description.getEndian() +
" but .sla says " + el.getAttribute("bigendian"));
}
}
uniqueBase = SpecXmlUtils.decodeLong(el.getAttribute("uniqbase"));
@@ -1149,9 +1160,7 @@ public class SleighLanguage implements Language {
@Override
public CompilerSpec getDefaultCompilerSpec() {
SleighCompilerSpecDescription compilerSpecDescription =
(SleighCompilerSpecDescription) description.getCompatibleCompilerSpecDescriptions()
.iterator()
.next();
(SleighCompilerSpecDescription) description.getCompatibleCompilerSpecDescriptions().iterator().next();
try {
return getCompilerSpecByID(compilerSpecDescription.getCompilerSpecID());
}
@@ -1315,8 +1324,8 @@ public class SleighLanguage implements Language {
if (matcher.find()) {
if (SystemUtilities.isInDevelopmentMode()) {
// Search across repositories in development mode
currentManual = Application
.findDataFileInAnyModule("manuals/" + matcher.group(1).trim());
currentManual = Application.findDataFileInAnyModule(
"manuals/" + matcher.group(1).trim());
}
if (currentManual == null) {
currentManual =
@@ -1585,8 +1594,7 @@ public class SleighLanguage implements Language {
}
else {
parallelHelper =
(ParallelInstructionLanguageHelper) helperClass.getDeclaredConstructor()
.newInstance();
(ParallelInstructionLanguageHelper) helperClass.getDeclaredConstructor().newInstance();
}
}
catch (Exception e) {
@@ -16,7 +16,6 @@
package ghidra.app.plugin.processors.sleigh;
import java.io.InputStream;
import java.io.StringReader;
import org.iso_relax.verifier.*;
import org.xml.sax.*;
@@ -27,32 +26,10 @@ import ghidra.util.Msg;
import utilities.util.FileResolutionResult;
import utilities.util.FileUtilities;
/**
* Validate SLEIGH related XML configuration files: .cspec .pspec and .ldefs
*
* A ResourceFile containing an XML document can be verified with one of the
* static methods:
* - validateCspecFile
* - validateLdefsFile
* - validatePspecFile
*
* Alternately the class can be instantiated, which will allocate a single verifier
* that can be run on multiple files.
*/
public class SleighLanguageValidator {
private static final ResourceFile ldefsRelaxSchemaFile;
private static final ResourceFile pspecRelaxSchemaFile;
private static final ResourceFile cspecRelaxSchemaFile;
public static final int CSPEC_TYPE = 1;
public static final int PSPEC_TYPE = 2;
public static final int LDEFS_TYPE = 3;
public static final int CSPECTAG_TYPE = 4;
private static final String LANGUAGE_TYPESTRING = "language definitions";
private static final String COMPILER_TYPESTRING = "compiler specification";
private static final String PROCESSOR_TYPESTRING = "processor specification";
private int verifierType;
private Verifier verifier;
static {
ResourceFile file = null;
@@ -92,107 +69,16 @@ public class SleighLanguageValidator {
cspecRelaxSchemaFile = file;
}
public SleighLanguageValidator(int type) {
verifierType = type;
ResourceFile schemaFile = null;
switch (type) {
case CSPEC_TYPE:
case CSPECTAG_TYPE:
schemaFile = cspecRelaxSchemaFile;
break;
case PSPEC_TYPE:
schemaFile = pspecRelaxSchemaFile;
break;
case LDEFS_TYPE:
schemaFile = ldefsRelaxSchemaFile;
break;
default:
throw new SleighException("Bad verifier type");
}
verifier = null;
try {
verifier = getVerifier(schemaFile);
}
catch (Exception e) {
throw new SleighException("Error creating verifier", e);
}
}
private String getTypeString() {
if (verifierType == PSPEC_TYPE) {
return PROCESSOR_TYPESTRING;
}
if (verifierType == LDEFS_TYPE) {
return LANGUAGE_TYPESTRING;
}
return COMPILER_TYPESTRING;
}
/**
* Verify the given file against this validator.
* @param specFile is the file
* @throws SleighException with an explanation if the file does not validate
*/
public void verify(ResourceFile specFile) throws SleighException {
FileResolutionResult result = FileUtilities.existsAndIsCaseDependent(specFile);
if (!result.isOk()) {
throw new SleighException(
specFile + " is not properly case dependent: " + result.getMessage());
}
try {
InputStream in = specFile.getInputStream();
verifier.setErrorHandler(new VerifierErrorHandler(specFile));
verifier.verify(new InputSource(in));
in.close();
}
catch (Exception e) {
throw new SleighException(
"Invalid " + getTypeString() + " file: " + specFile.getAbsolutePath(), e);
}
}
/**
* Verify an XML document as a string against this validator.
* Currently this only supports verifierType == CSPECTAG_TYPE.
* @param title is a description of the document
* @param document is the XML document body
* @throws SleighException with an explanation if the document does not validate
*/
public void verify(String title, String document) throws SleighException {
if (verifierType != CSPECTAG_TYPE) {
throw new SleighException("Only cspec tag verification is supported");
}
StringBuilder buffer = new StringBuilder();
buffer.append("<compiler_spec>\n");
buffer.append("<default_proto>\n");
buffer.append("<prototype name=\"a\" extrapop=\"0\" stackshift=\"0\">\n");
buffer.append("<input/><output/>\n");
buffer.append("</prototype>\n");
buffer.append("</default_proto>\n");
buffer.append(document);
buffer.append("</compiler_spec>\n");
ErrorHandler errorHandler = new VerifierErrorHandler(title, 6);
StringReader reader = new StringReader(buffer.toString());
verifier.setErrorHandler(errorHandler);
try {
verifier.verify(new InputSource(reader));
}
catch (Exception e) {
throw new SleighException("Invalid " + getTypeString() + ": " + title, e);
}
}
public static void validateLdefsFile(ResourceFile ldefsFile) throws SleighException {
validateSleighFile(ldefsRelaxSchemaFile, ldefsFile, LANGUAGE_TYPESTRING);
validateSleighFile(ldefsRelaxSchemaFile, ldefsFile, "language definitions");
}
public static void validatePspecFile(ResourceFile pspecFile) throws SleighException {
validateSleighFile(pspecRelaxSchemaFile, pspecFile, PROCESSOR_TYPESTRING);
validateSleighFile(pspecRelaxSchemaFile, pspecFile, "processor specification");
}
public static void validateCspecFile(ResourceFile cspecFile) throws SleighException {
validateSleighFile(cspecRelaxSchemaFile, cspecFile, COMPILER_TYPESTRING);
validateSleighFile(cspecRelaxSchemaFile, cspecFile, "compiler specification");
}
private static void validateSleighFile(ResourceFile relaxSchemaFile,
@@ -200,8 +86,8 @@ public class SleighLanguageValidator {
FileResolutionResult result = FileUtilities.existsAndIsCaseDependent(fileToValidate);
if (!result.isOk()) {
throw new SleighException(
fileToValidate + " is not properly case dependent: " + result.getMessage());
throw new SleighException(fileToValidate + " is not properly case dependent: " +
result.getMessage());
}
Verifier verifier = null;
@@ -213,7 +99,7 @@ public class SleighLanguageValidator {
}
try {
InputStream in = fileToValidate.getInputStream();
verifier.setErrorHandler(new VerifierErrorHandler(fileToValidate));
verifier.setErrorHandler(new MyErrorHandler(fileToValidate));
verifier.verify(new InputSource(in));
in.close();
}
@@ -230,18 +116,11 @@ public class SleighLanguageValidator {
return verifier;
}
private static class VerifierErrorHandler implements ErrorHandler {
final String documentTitle;
int lineNumberBase;
private static class MyErrorHandler implements ErrorHandler {
final ResourceFile file;
public VerifierErrorHandler(ResourceFile file) {
documentTitle = file.toString();
lineNumberBase = 0;
}
public VerifierErrorHandler(String title, int base) {
documentTitle = title;
lineNumberBase = base;
public MyErrorHandler(ResourceFile file) {
this.file = file;
}
@Override
@@ -251,10 +130,10 @@ public class SleighLanguageValidator {
@Override
public void error(SAXParseException e) throws SAXException {
int lineno = e.getLineNumber() - lineNumberBase;
Msg.error(SleighLanguageValidator.class,
"Error validating " + documentTitle + " at " + lineno + ":" + e.getColumnNumber(),
e);
Msg.error(
SleighLanguageValidator.class,
"Error validating " + file + " at " + e.getLineNumber() + ":" +
e.getColumnNumber(), e);
throw e;
}
@@ -1,76 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.plugin.processors.sleigh;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.JComponent;
import ghidra.framework.options.*;
import ghidra.program.database.ProgramDB;
import ghidra.util.exception.InvalidInputException;
import ghidra.util.task.TaskMonitor;
public class SpecExtensionEditor implements OptionsEditor, PropertyChangeListener {
private ProgramDB program;
private PropertyChangeListener listener;
private SpecExtensionPanel panel;
public SpecExtensionEditor(ProgramDB program) {
this.program = program;
}
@Override
public void apply() throws InvalidInputException {
panel.apply(TaskMonitor.DUMMY);
}
@Override
public void cancel() {
panel.cancel();
}
@Override
public void reload() {
// doesn't respond to reload
}
@Override
public void setOptionsPropertyChangeListener(PropertyChangeListener listener) {
this.listener = listener;
}
@Override
public JComponent getEditorComponent(Options options, EditorStateFactory editorStateFactory) {
panel = new SpecExtensionPanel(program, this);
return panel;
}
@Override
public void dispose() {
// stub
}
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (listener != null) {
listener.propertyChange(evt);
}
}
}
@@ -1,5 +1,6 @@
/* ###
* 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.
@@ -19,90 +20,47 @@
*/
package ghidra.app.plugin.processors.sleigh.template;
import java.util.ArrayList;
import ghidra.program.model.address.AddressFactory;
import ghidra.program.model.lang.UnknownInstructionException;
import ghidra.util.xml.SpecXmlUtils;
import ghidra.xml.XmlElement;
import ghidra.xml.XmlPullParser;
import java.util.ArrayList;
/**
* A constructor template, representing the semantic action of a SLEIGH constructor, without
* its final context. The constructor template is made up of a list of p-code op templates,
* which are in turn made up of varnode templates.
* This is one step removed from the final array of PcodeOp objects, but:
* - Constants may still need to incorporate context dependent address resolution and relative offsets.
* - Certain p-code operations may still need expansion to include a dynamic LOAD or STORE operation.
* - The list may hold "build" directives for sub-constructor templates.
* - The list may still hold "label" information for the final resolution of relative jump offsets.
*
* The final PcodeOps are produced by handing this to the build() method of PcodeEmit which has
* the InstructionContext necessary for final resolution.
*
* Placeholder for what resolves to a list of PcodeOps and
* a FixedHandle. It represents the semantic action of a constructor
* and its return value for a particular InstructionContext
*/
public class ConstructTpl {
private int numlabels = 0; // Number of relative-offset labels in this template
private int numlabels=0;
private OpTpl[] vec; // The semantic action of constructor
private HandleTpl result; // The final semantic value
/**
* Constructor for use with restoreXML
*/
public ConstructTpl() {
}
/**
* Manually build a constructor template. This is useful for building constructor templates
* outside of the normal SLEIGH pipeline, as for an internally created InjectPayload.
* @param opvec is the list of p-code op templates making up the constructor
*/
public ConstructTpl(OpTpl[] opvec) {
vec = opvec;
result = null;
}
/**
* @return the number of labels needing resolution in this template
*/
public int getNumLabels() {
return numlabels;
}
/**
* @return the list of p-code op templates making up this constructor template
*/
public OpTpl[] getOpVec() {
return vec;
}
/**
* @return the (possibly dynamic) location of the final semantic value produced by this constructor
*/
public HandleTpl getResult() {
return result;
}
/**
* Restore this template from a \<construct_tpl> tag in an XML stream.
* @param parser is the XML stream
* @param factory is for manufacturing Address objects
* @return the constructor section id described by the tag
* @throws UnknownInstructionException if the p-code templates contain unknown op-codes
*/
public int restoreXml(XmlPullParser parser, AddressFactory factory)
throws UnknownInstructionException {
public int getNumLabels() { return numlabels; }
public OpTpl[] getOpVec() { return vec; }
public HandleTpl getResult() { return result; }
public int restoreXml(XmlPullParser parser,AddressFactory factory) throws UnknownInstructionException {
int sectionid = -1;
XmlElement el = parser.start("construct_tpl");
XmlElement el = parser.start("construct_tpl");
// String delaystr = el.getAttribute("delay");
// if (delaystr != null)
// delayslot = SpecXmlUtils.decodeInt(delaystr);
String nmlabelstr = el.getAttribute("labels");
if (nmlabelstr != null) {
if (nmlabelstr != null)
numlabels = SpecXmlUtils.decodeInt(nmlabelstr);
}
String sectionidstr = el.getAttribute("section");
if (sectionidstr != null) {
if (sectionidstr != null)
sectionid = SpecXmlUtils.decodeInt(sectionidstr);
}
XmlElement handel = parser.peek();
if (handel.getName().equals("null")) {
result = null;
@@ -110,12 +68,12 @@ public class ConstructTpl {
}
else {
result = new HandleTpl();
result.restoreXml(parser, factory);
result.restoreXml(parser,factory);
}
ArrayList<Object> oplist = new ArrayList<>();
while (!parser.peek().isEnd()) {
ArrayList<Object> oplist = new ArrayList<Object>();
while(!parser.peek().isEnd()) {
OpTpl op = new OpTpl();
op.restoreXml(parser, factory);
op.restoreXml(parser,factory);
oplist.add(op);
}
vec = new OpTpl[oplist.size()];
@@ -123,5 +81,5 @@ public class ConstructTpl {
parser.end(el);
return sectionid;
}
}

Some files were not shown because too many files have changed in this diff Show More