mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-05-21 12:59:48 +08:00
Revert "Merge remote-tracking branch 'origin/GP-653_UserDefinedCspec--SQUASHED'"
This commit is contained in:
+5
-5
@@ -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);
|
||||
|
||||
+1
-5
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 ®name); ///< 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>
|
||||
|
||||
+3
-5
@@ -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">“Prototype Model”</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">“Specification Extensions”</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">“Specification Extensions”</a>.
|
||||
<span class="emphasis"><em>compiler specification</em></span> for the Program.
|
||||
</p>
|
||||
</dd>
|
||||
</dl></div>
|
||||
|
||||
+4
-181
@@ -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">“Specification Extensions”</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">“Specification Extensions”</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"><Root>/Ghidra/Processors/<Family>/data/languages</code>
|
||||
</div>
|
||||
<p>
|
||||
where <code class="code"><Root></code> represents the root directory of the Ghidra installation and
|
||||
<code class="code"><Family></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"><prototype> - describing a specific calling convention</li>
|
||||
<li class="listitem" style="list-style-type: none"><callfixup> - describing a Call-fixup</li>
|
||||
<li class="listitem" style="list-style-type: none"><callotherfixup> - 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">“Specification Extensions”</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>
|
||||
|
||||
+1
-1
@@ -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">
|
||||
|
||||
+5
-287
@@ -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 -> Options for <Program></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">“Program Options”</a>
|
||||
that only affect the decompiler. Picking the <a class="xref" href="DecompilerOptions.html#ExtensionOptions" title="Specification Extensions">“Specification Extensions”</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">“Program Options”</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">“SLEIGH Specification Files”</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">“Prototype Model”</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">“Function Prototypes”</a> for how they affect decompilation.
|
||||
</p>
|
||||
<p>
|
||||
The XML tag, <code class="code"><prototype></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">
|
||||
<prototype name="__stdcall" extrapop="unknown" stackshift="4">
|
||||
<input>
|
||||
<pentry minsize="1" maxsize="500" align="4">
|
||||
<addr offset="4" space="stack"/>
|
||||
</pentry>
|
||||
</input>
|
||||
<output>
|
||||
...
|
||||
</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">“Function Prototypes”</a>.
|
||||
</p>
|
||||
<p>
|
||||
The <code class="code"><callfixup></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">
|
||||
<callfixup name="EH_prolog3">
|
||||
<pcode>
|
||||
<body><![CDATA<
|
||||
EBP = ESP + 4;
|
||||
tmp = * EBP;
|
||||
ESP = ESP - tmp;
|
||||
ESP = ESP - 24;
|
||||
]]></body>
|
||||
</pcode>
|
||||
</callfixup>
|
||||
</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">“User-defined P-code Operations - CALLOTHER”</a>.
|
||||
</p>
|
||||
<p>
|
||||
The <code class="code"><callotherfixup></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">
|
||||
<callotherfixup targetop="dynamicPush">
|
||||
<pcode>
|
||||
<input name="amount"/>
|
||||
<body><![CDATA[
|
||||
RSP = RSP + amount;
|
||||
]]></body>
|
||||
</pcode>
|
||||
</callotherfixup>
|
||||
</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><blank></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"><prototype></code>, <code class="code"><callfixup></code>, or <code class="code"><callotherfixup></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">“SLEIGH Specification Files”</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>
|
||||
|
||||
+1
-1
@@ -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">
|
||||
|
||||
+25
-37
@@ -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();
|
||||
}
|
||||
|
||||
+38
-55
@@ -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");
|
||||
}
|
||||
|
||||
+48
-94
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
-6
@@ -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() {
|
||||
|
||||
+6
-2
@@ -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.*;
|
||||
|
||||
-4
@@ -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();
|
||||
|
||||
+10
-26
@@ -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() {
|
||||
|
||||
+2
-4
@@ -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) {
|
||||
|
||||
-31
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
+34
-1
@@ -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(),
|
||||
|
||||
-259
@@ -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);
|
||||
}
|
||||
}
|
||||
+16
-15
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-2
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+84
-76
@@ -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) {
|
||||
|
||||
+14
-135
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
-76
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
-709
File diff suppressed because it is too large
Load Diff
+26
-68
@@ -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
Reference in New Issue
Block a user