From a5d4ca3cab650b95fa1b9c7bfc21e95d77d92e1c Mon Sep 17 00:00:00 2001
From: caheckman <48068198+caheckman@users.noreply.github.com>
Date: Tue, 2 Feb 2021 13:07:54 -0500
Subject: [PATCH] Program specific, user-defined, cspec extensions
Documentation for spec extensions
Handle extensions with parse errors
Export button for spec extensions
Pop-up dialog for parse errors in user-defined specification extensions
GP-653 corrected some minor issues and established new ProgramDB version
make incremental initialization constructor for AddressSized private
Make AddressSized fields private
More adjustments to AddressSized
Review fixes for BasicCompilerSpec
Take restoreXml out of DataOrganization interface
Remove restoreXml from BitFieldPacking interface
More review fixes
Prevent callotherfixup extension with non-existent target
Suggested export name
More documentation for SpecExtension
Support for undo/redo with spec extensions
Documentation for ConstructTpl
Split out ProgramCompilerSpec and other changes for review
Changes after next round of reviews
---
.../core/disassembler/CallFixupAnalyzer.java | 10 +-
.../function/editor/FunctionEditorDialog.java | 6 +-
.../program/util/SymbolicPropogator.java | 57 +-
Ghidra/Features/Decompiler/build.gradle | 20 +-
.../Decompiler/certification.manifest | 1 +
.../ghidra_scripts/TurnOnLanguage.java | 13 +-
.../src/decompile/cpp/architecture.cc | 20 +
.../Decompiler/src/decompile/cpp/fspec.hh | 2 +-
.../src/decompile/cpp/ghidra_arch.cc | 10 +-
.../src/decompile/cpp/ghidra_arch.hh | 3 +-
.../src/decompile/cpp/ghidra_process.cc | 4 +
.../src/decompile/cpp/inject_sleigh.cc | 24 +-
.../src/decompile/cpp/inject_sleigh.hh | 1 +
.../Decompiler/src/decompile/cpp/userop.cc | 6 +-
.../Decompiler/src/decompile/cpp/xml_arch.cc | 6 +
.../Decompiler/src/main/doc/commonprofile.xsl | 6 +
.../Decompiler/src/main/doc/cspec_html.xsl | 2 +-
.../src/main/doc/decompileplugin.xml | 456 ++++++-
.../src/main/doc/decompileplugin_html.xsl | 2 +-
.../src/main/doc/decompileplugin_pdf.xsl | 4 +-
.../Decompiler/src/main/doc/main_html.xsl | 2 +-
.../Decompiler/src/main/doc/pcoderef_html.xsl | 2 +-
.../Decompiler/src/main/doc/pcoderef_pdf.xsl | 2 +-
.../Decompiler/src/main/doc/sleigh_html.xsl | 2 +-
.../Decompiler/src/main/doc/sleigh_pdf.xsl | 2 +-
.../src/main/help/help/TOC_Source.xml | 9 +-
.../DecompilerAnnotations.html | 8 +-
.../DecompilePlugin/DecompilerConcepts.html | 185 ++-
.../DecompilePlugin/DecompilerIntro.html | 2 +-
.../DecompilePlugin/DecompilerOptions.html | 292 +++-
.../DecompilePlugin/DecompilerWindow.html | 2 +-
.../app/decompiler/DecompInterface.java | 62 +-
.../app/decompiler/DecompileCallback.java | 93 +-
.../ghidra/app/decompiler/DecompileDebug.java | 142 +-
.../app/decompiler/DecompileOptions.java | 10 +-
.../app/decompiler/DecompileProcess.java | 8 +-
.../core/decompile/DecompilePlugin.java | 4 +
.../core/decompile/DecompilerProvider.java | 34 +-
.../validator/DecompilerValidator.java | 6 +-
.../decompile/AbstractDecompilerTest.java | 31 +
.../plugin/core/decompile/HighSymbolTest.java | 35 +-
.../core/decompile/SpecExtensionTest.java | 259 ++++
.../dex/analyzer/DexHeaderFormatAnalyzer.java | 31 +-
.../framework/data/DomainObjectAdapterDB.java | 3 +-
.../java/ghidra/framework/data/OptionsDB.java | 4 +-
.../processors/sleigh/SleighLanguage.java | 160 ++-
.../sleigh/SleighLanguageValidator.java | 149 ++-
.../sleigh/SpecExtensionEditor.java | 76 ++
.../processors/sleigh/SpecExtensionPanel.java | 709 ++++++++++
.../sleigh/template/ConstructTpl.java | 94 +-
.../program/database/ProgramCompilerSpec.java | 374 ++++++
.../ghidra/program/database/ProgramDB.java | 60 +-
.../program/database/SpecExtension.java | 785 +++++++++++
.../program/database/function/FunctionDB.java | 22 +-
.../database/function/FunctionManagerDB.java | 5 +-
.../program/disassemble/Disassembler.java | 11 +-
.../program/model/data/BitFieldPacking.java | 1 -
.../model/data/BitFieldPackingImpl.java | 73 +
.../model/data/DataOrganizationImpl.java | 292 +++-
.../program/model/lang/BasicCompilerSpec.java | 1178 ++++++++++-------
.../program/model/lang/CompilerSpec.java | 100 +-
.../program/model/lang/ContextSetting.java | 164 ++-
.../program/model/lang/InjectContext.java | 55 +-
.../program/model/lang/InjectPayload.java | 72 +-
.../model/lang/InjectPayloadCallfixup.java | 86 +-
.../lang/InjectPayloadCallfixupError.java | 39 +
.../model/lang/InjectPayloadCallother.java | 44 +-
.../lang/InjectPayloadCallotherError.java | 43 +
.../model/lang/InjectPayloadJumpAssist.java | 48 +
.../model/lang/InjectPayloadSegment.java | 137 ++
.../model/lang/InjectPayloadSleigh.java | 320 +++--
.../ghidra/program/model/lang/ParamEntry.java | 315 +++--
.../ghidra/program/model/lang/ParamList.java | 26 +-
.../program/model/lang/ParamListStandard.java | 149 ++-
.../model/lang/PcodeInjectLibrary.java | 389 +++++-
.../program/model/lang/PrototypeModel.java | 408 +++++-
.../model/lang/PrototypeModelError.java | 31 +
.../model/lang/PrototypeModelMerged.java | 140 +-
.../listing/InstructionPcodeOverride.java | 5 +-
.../program/model/pcode/AddressXML.java | 664 ++++++++++
.../model/pcode/FunctionPrototype.java | 9 +-
.../model/pcode/HighExternalSymbol.java | 2 +-
.../program/model/pcode/HighFunction.java | 33 +-
.../model/pcode/HighFunctionShellSymbol.java | 2 +-
.../program/model/pcode/HighParamID.java | 36 +-
.../ghidra/program/model/pcode/JumpTable.java | 72 +-
.../program/model/pcode/MappedEntry.java | 5 +-
.../model/pcode/PcodeDataTypeManager.java | 2 +-
.../ghidra/program/model/pcode/Varnode.java | 237 +---
.../util/LanguageTranslatorAdapter.java | 50 +-
.../inject/InjectPayloadDexParameters.java | 83 +-
.../dex/inject/InjectPayloadDexRange.java | 47 +-
.../dex/inject/PcodeInjectLibraryDex.java | 37 +-
.../app/util/pcodeInject/InjectGetField.java | 5 -
.../app/util/pcodeInject/InjectGetStatic.java | 5 -
.../util/pcodeInject/InjectInvokeDynamic.java | 5 -
.../pcodeInject/InjectInvokeInterface.java | 5 -
.../util/pcodeInject/InjectInvokeSpecial.java | 5 -
.../util/pcodeInject/InjectInvokeStatic.java | 5 -
.../util/pcodeInject/InjectInvokeVirtual.java | 5 -
.../app/util/pcodeInject/InjectLdc.java | 5 -
.../pcodeInject/InjectMultiANewArray.java | 5 -
.../util/pcodeInject/InjectPayloadJava.java | 48 +-
.../InjectPayloadJavaParameters.java | 81 +-
.../app/util/pcodeInject/InjectPutField.java | 5 -
.../app/util/pcodeInject/InjectPutStatic.java | 5 -
.../pcodeInject/PcodeInjectLibraryJava.java | 84 +-
.../javaclass/analyzers/JavaAnalyzer.java | 4 +-
108 files changed, 7997 insertions(+), 1997 deletions(-)
create mode 100644 Ghidra/Features/Decompiler/src/main/doc/commonprofile.xsl
create mode 100644 Ghidra/Features/Decompiler/src/test.slow/java/ghidra/app/plugin/core/decompile/SpecExtensionTest.java
create mode 100644 Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/SpecExtensionEditor.java
create mode 100644 Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/SpecExtensionPanel.java
create mode 100644 Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/ProgramCompilerSpec.java
create mode 100644 Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/SpecExtension.java
create mode 100644 Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/InjectPayloadCallfixupError.java
create mode 100644 Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/InjectPayloadCallotherError.java
create mode 100644 Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/InjectPayloadJumpAssist.java
create mode 100644 Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/InjectPayloadSegment.java
create mode 100644 Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/PrototypeModelError.java
create mode 100644 Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/AddressXML.java
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/disassembler/CallFixupAnalyzer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/disassembler/CallFixupAnalyzer.java
index 36931f31b0..60f8c68024 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/disassembler/CallFixupAnalyzer.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/disassembler/CallFixupAnalyzer.java
@@ -101,8 +101,8 @@ public class CallFixupAnalyzer extends AbstractAnalyzer {
if (mustFix) {
PcodeInjectLibrary snippetLibrary =
program.getCompilerSpec().getPcodeInjectLibrary();
- InjectPayload callFixup = snippetLibrary.getPayload(InjectPayload.CALLFIXUP_TYPE,
- callFixupApplied, program, null);
+ InjectPayload callFixup =
+ snippetLibrary.getPayload(InjectPayload.CALLFIXUP_TYPE, callFixupApplied);
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, program, null);
+ snippetLibrary.getPayload(InjectPayload.CALLFIXUP_TYPE, fixupName);
List callFixupTargets = ((InjectPayloadCallfixup) payload).getTargets();
for (String name : callFixupTargets) {
cachedTargetFixupMap.put(name, fixupName);
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/FunctionEditorDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/FunctionEditorDialog.java
index da0ecfab24..a8d85b1a9e 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/FunctionEditorDialog.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/FunctionEditorDialog.java
@@ -359,6 +359,9 @@ public class FunctionEditorDialog extends DialogComponentProvider implements Mod
}
private JComponent createCallFixupComboPanel() {
+
+ JPanel panel = new JPanel();
+
callFixupComboBox = new GComboBox<>();
String[] callFixupNames = model.getCallFixupNames();
@@ -377,7 +380,8 @@ public class FunctionEditorDialog extends DialogComponentProvider implements Mod
callFixupComboBox.setEnabled(false);
}
- return callFixupComboBox;
+ panel.add(callFixupComboBox);
+ return panel;
}
private Component buildTable() {
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/program/util/SymbolicPropogator.java b/Ghidra/Features/Base/src/main/java/ghidra/program/util/SymbolicPropogator.java
index 1d2c2b5a3f..0ec9498847 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/program/util/SymbolicPropogator.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/program/util/SymbolicPropogator.java
@@ -405,8 +405,9 @@ 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();
@@ -834,8 +835,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);
}
@@ -873,8 +874,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 ??
@@ -957,8 +958,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);
}
@@ -1074,8 +1075,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
}
}
@@ -1202,8 +1203,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;
@@ -1211,8 +1212,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;
@@ -1315,8 +1316,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;
@@ -1334,8 +1335,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;
@@ -1344,8 +1345,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;
@@ -1353,8 +1354,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;
@@ -1571,7 +1572,7 @@ public class SymbolicPropogator {
PcodeInjectLibrary snippetLibrary = prog.getCompilerSpec().getPcodeInjectLibrary();
InjectPayload payload =
- snippetLibrary.getPayload(InjectPayload.CALLFIXUP_TYPE, callFixupName, prog, null);
+ snippetLibrary.getPayload(InjectPayload.CALLFIXUP_TYPE, callFixupName);
if (payload == null) {
return null;
}
@@ -1598,7 +1599,7 @@ public class SymbolicPropogator {
PcodeInjectLibrary snippetLibrary = prog.getCompilerSpec().getPcodeInjectLibrary();
InjectPayload payload =
- snippetLibrary.getPayload(InjectPayload.CALLMECHANISM_TYPE, injectionName, prog, null);
+ snippetLibrary.getPayload(InjectPayload.CALLMECHANISM_TYPE, injectionName);
if (payload == null) {
return null;
}
@@ -1843,14 +1844,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;
}
}
diff --git a/Ghidra/Features/Decompiler/build.gradle b/Ghidra/Features/Decompiler/build.gradle
index a426377b0a..85a49229f9 100644
--- a/Ghidra/Features/Decompiler/build.gradle
+++ b/Ghidra/Features/Decompiler/build.gradle
@@ -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" /usr/share/sgml/docbook/xsl-stylesheets/profiling/profile.xsl decompileplugin.xml 2>&1
+ xsltproc --output $buildDir/decomp_noscaling.xml --stringparam profile.condition "noscaling" commonprofile.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 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
+ 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
echo '** Building decompileplugin.fo **'
- 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
+ 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
echo '** Building decompileplugin.pdf **'
- fop decompileplugin.fo decompileplugin.pdf 2>&1
+ fop $buildDir/decompileplugin.fo $buildDir/decompileplugin.pdf 2>&1
echo '** Done. **'
"""
diff --git a/Ghidra/Features/Decompiler/certification.manifest b/Ghidra/Features/Decompiler/certification.manifest
index f965b0d4c3..9a6aa4192b 100644
--- a/Ghidra/Features/Decompiler/certification.manifest
+++ b/Ghidra/Features/Decompiler/certification.manifest
@@ -30,6 +30,7 @@ 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|
diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/TurnOnLanguage.java b/Ghidra/Features/Decompiler/ghidra_scripts/TurnOnLanguage.java
index 2a86ffda93..0a29834439 100644
--- a/Ghidra/Features/Decompiler/ghidra_scripts/TurnOnLanguage.java
+++ b/Ghidra/Features/Decompiler/ghidra_scripts/TurnOnLanguage.java
@@ -15,18 +15,17 @@
*/
import ghidra.app.script.GhidraScript;
import ghidra.framework.options.Options;
-import ghidra.program.model.lang.BasicCompilerSpec;
+import ghidra.program.database.ProgramCompilerSpec;
public class TurnOnLanguage extends GhidraScript {
@Override
protected void run() throws Exception {
- Options decompilerPropertyList = currentProgram.getOptions(BasicCompilerSpec.DECOMPILER_PROPERTY_LIST_NAME);
- decompilerPropertyList.registerOption(
- BasicCompilerSpec.DECOMPILER_OUTPUT_LANGUAGE,
- BasicCompilerSpec.DECOMPILER_OUTPUT_DEF,
- null,
- BasicCompilerSpec.DECOMPILER_OUTPUT_DESC);
+ Options decompilerPropertyList =
+ currentProgram.getOptions(ProgramCompilerSpec.DECOMPILER_PROPERTY_LIST_NAME);
+ decompilerPropertyList.registerOption(ProgramCompilerSpec.DECOMPILER_OUTPUT_LANGUAGE,
+ ProgramCompilerSpec.DECOMPILER_OUTPUT_DEF, null,
+ ProgramCompilerSpec.DECOMPILER_OUTPUT_DESC);
}
}
diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.cc
index e04d172dab..56dd7f979f 100644
--- a/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.cc
+++ b/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.cc
@@ -1218,6 +1218,26 @@ void Architecture::parseCompilerConfig(DocumentStorage &store)
else if (elname == "inferptrbounds")
parseInferPtrBounds(*iter);
}
+
+ el = store.getTag("specextensions"); // Look for any user-defined configuration document
+ if (el != (const Element *)0) {
+ const List &userlist(el->getChildren());
+ for(iter=userlist.begin();iter!=userlist.end();++iter) {
+ const string &elname( (*iter)->getName() );
+ if (elname == "prototype")
+ parseProto(*iter);
+ else if (elname == "callfixup") {
+ pcodeinjectlib->restoreXmlInject(archid+" : compiler spec", (*iter)->getAttributeValue("name"),
+ InjectPayload::CALLFIXUP_TYPE, *iter);
+ }
+ else if (elname == "callotherfixup") {
+ userops.parseCallOtherFixup(*iter,this);
+ }
+ else if (elname == "global")
+ globaltags.push_back(*iter);
+ }
+ }
+
// tags instantiate the base symbol table
// They need to know about all spaces, so it must come
// after parsing of and
diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/fspec.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/fspec.hh
index 9a592cb4a2..974e733e22 100644
--- a/Ghidra/Features/Decompiler/src/decompile/cpp/fspec.hh
+++ b/Ghidra/Features/Decompiler/src/decompile/cpp/fspec.hh
@@ -314,7 +314,7 @@ public:
enum {
unaffected = 1, ///< The sub-function does not change the value at all
killedbycall = 2, ///< The memory is changed and is completely unrelated to its original value
- return_address = 3, ///< The memory is being used to pass back a return value from the sub-function
+ return_address = 3, ///< The memory is being used to store the return address
unknown_effect = 4 ///< An unknown effect (indicates the absence of an EffectRecord)
};
private:
diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_arch.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_arch.cc
index d34513ef04..b72a8093db 100644
--- a/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_arch.cc
+++ b/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_arch.cc
@@ -284,7 +284,7 @@ void ArchitectureGhidra::buildSpecFile(DocumentStorage &store)
istringstream cstream(cspecxml);
doc = store.parseDocument(cstream);
store.registerTag(doc->getRoot());
-
+
istringstream tstream(tspecxml);
doc = store.parseDocument(tstream);
store.registerTag(doc->getRoot());
@@ -293,10 +293,10 @@ void ArchitectureGhidra::buildSpecFile(DocumentStorage &store)
doc = store.parseDocument(corestream);
store.registerTag(doc->getRoot());
- pspecxml = ""; // Strings aren't used again free memory
- cspecxml = "";
- tspecxml = "";
- corespecxml = "";
+ pspecxml.clear(); // Strings aren't used again free memory
+ cspecxml.clear();
+ tspecxml.clear();
+ corespecxml.clear();
}
void ArchitectureGhidra::postSpecFile(void)
diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_arch.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_arch.hh
index f796c7ea76..0953288662 100644
--- a/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_arch.hh
+++ b/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_arch.hh
@@ -82,7 +82,8 @@ class ArchitectureGhidra : public Architecture {
virtual void postSpecFile(void);
virtual void resolveArchitecture(void);
public:
- ArchitectureGhidra(const string &pspec,const string &cspec,const string &tspec,const string &corespec,istream &i,ostream &o);
+ ArchitectureGhidra(const string &pspec,const string &cspec,const string &tspec,const string &corespec,
+ istream &i,ostream &o);
const string &getWarnings(void) const { return warnings; } ///< Get warnings produced by the last decompilation
void clearWarnings(void) { warnings.clear(); } ///< Clear warnings
Document *getRegister(const string ®name); ///< Retrieve a register description given a name
diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_process.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_process.cc
index e78b0c0ced..46efe6eb0f 100644
--- a/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_process.cc
+++ b/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_process.cc
@@ -174,6 +174,10 @@ void RegisterProgram::rawAction(void)
}
}
ghidra = new ArchitectureGhidra(pspec,cspec,tspec,corespec,sin,sout);
+ pspec.clear();
+ cspec.clear();
+ tspec.clear();
+ corespec.clear();
DocumentStorage store; // temp storage of initialization xml docs
ghidra->init(store);
diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/inject_sleigh.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/inject_sleigh.cc
index 4a1e44dbf8..b72d089d2a 100644
--- a/Ghidra/Features/Decompiler/src/decompile/cpp/inject_sleigh.cc
+++ b/Ghidra/Features/Decompiler/src/decompile/cpp/inject_sleigh.cc
@@ -293,6 +293,23 @@ int4 PcodeInjectLibrarySleigh::registerDynamicInject(InjectPayload *payload)
return id;
}
+/// \brief Force a payload to be dynamic for debug purposes
+///
+/// Debug information may include inject information for payloads that aren't dynamic.
+/// We substitute a dynamic payload so that analysis uses the debug info to inject, rather
+/// than the hard-coded payload information.
+/// \param injectid is the id of the payload to treat dynamic
+/// \return the new dynamic payload object
+InjectPayloadDynamic *PcodeInjectLibrarySleigh::forceDebugDynamic(int4 injectid)
+
+{
+ InjectPayload *oldPayload = injection[injectid];
+ InjectPayloadDynamic *newPayload = new InjectPayloadDynamic(glb,oldPayload->getName(),oldPayload->getType());
+ delete oldPayload;
+ injection[injectid] = newPayload;
+ return newPayload;
+}
+
void PcodeInjectLibrarySleigh::parseInject(InjectPayload *payload)
{
@@ -399,9 +416,10 @@ void PcodeInjectLibrarySleigh::restoreDebug(const Element *el)
s.unsetf(ios::dec | ios::hex | ios::oct);
s >> type;
int4 id = getPayloadId(type,name);
- InjectPayloadDynamic *payload = (InjectPayloadDynamic *)getPayload(id);
- if (payload->getSource() != "dynamic")
- throw LowlevelError("Mismatch with debug inject XML");
+ InjectPayloadDynamic *payload = dynamic_cast(getPayload(id));
+ if (payload == (InjectPayloadDynamic *)0) {
+ payload = forceDebugDynamic(id);
+ }
payload->restoreEntry(subel);
}
}
diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/inject_sleigh.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/inject_sleigh.hh
index ad6f44bff2..600215c658 100644
--- a/Ghidra/Features/Decompiler/src/decompile/cpp/inject_sleigh.hh
+++ b/Ghidra/Features/Decompiler/src/decompile/cpp/inject_sleigh.hh
@@ -91,6 +91,7 @@ class PcodeInjectLibrarySleigh : public PcodeInjectLibrary {
vector 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);
diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/userop.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/userop.cc
index e08b43f037..0d13d3a7b6 100644
--- a/Ghidra/Features/Decompiler/src/decompile/cpp/userop.cc
+++ b/Ghidra/Features/Decompiler/src/decompile/cpp/userop.cc
@@ -216,10 +216,10 @@ void SegmentOp::restoreXml(const Element *el)
throw LowlevelError("Bad segment pattern tag: "+subel->getName());
}
if (injectId < 0)
- throw LowlevelError("Missing child in tag");
+ throw LowlevelError("Missing child in tag");
InjectPayload *payload = glb->pcodeinjectlib->getPayload(injectId);
if (payload->sizeOutput() != 1)
- throw LowlevelError(" child of tag must declare one
In the absence of parameter and return value annotations, the decompiler will use the prototype model as
@@ -1042,7 +1043,8 @@
Call-fixups are specified by name. The name and associated p-code chunk are typically defined in the
- compiler specification for the Program.
+ compiler specification for the Program. Users can extend the available set
+ of call-fixups. See “Specification Extensions”.
+ P-code allows for additional, processor specific, operations referred to
+ as user-defined 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.
+
+
+ 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.
+
+
+ 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
+ Callother-Fixup, 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 “Specification Extensions”)
+
+
+
+
+
Internal Decompiler Functions
@@ -1052,10 +1081,13 @@
use of multiple models. Subsequently, each distinct model has a name like __stdcall or
__thiscall. 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 “Specification Extensions”.
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.
+ the sub-concepts of the model may be relevant to reverse engineers. Concepts that a prototype
+ model encapsulates include:
@@ -1107,5 +1139,150 @@
+
+
+SLEIGH Specification Files
+
+
+ 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:
+
+
+
+
+ Disassemble machine instructions from the underlying bytes and
+
+
+ Produce the raw p-code consumed by the decompiler and other analyzers.
+
+
+
+
+
+
+ Specification files are selected based on the Language Id
+ assigned to the Program at the time it is imported into Ghidra.
+ (See Import Program)
+
+
+
+
x86:LE:32:default:windows
+
AARCH64:LE:64:default:v8A:default
+
MIPS:BE:32:micro:default
+
+
+
+ A Language Id is a label with these 5 formal fields, separated
+ by a ':' character:
+
+
+
+
Processor family
+
Endianess
+
Size of the address bus
+
Process variant
+
Compiler producing the Program
+
+
+
+ A field with the value 'default' indicates either the preferred processor variant or the preferred compiler.
+
+
+ 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
+
+ where <Root> represents the root directory of the Ghidra installation and
+ <Family> is the processor family.
+
+
+ There are several types of specification files that are distinguishable by their suffix.
+ These include:
+
+
+
+
SLEIGH files - *.slaspec or *.sinc
+
+
+ These are the human readable SLEIGH language files. A single specification is
+ rooted in one of the *.slaspec files, which may recursively include
+ one or more *.sinc files. The format of these files is described
+ in the document "SLEIGH: A Language for Rapid Processor Specification".
+
+
+
Compiled SLEIGH files - *.sla
+
+
+ This is a compiled form of a single SLEIGH specification. It is produced
+ automatically by Ghidra from the corresponding *.slaspec.
+
+
+
Compiler specification files - *.cspec
+
+
+ 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:
+
+
+
+
+
<prototype> - describing a specific calling convention
+
<callfixup> - describing a Call-fixup
+
<callotherfixup> - describing a Callother-fixup
+
+
+
+
+
Processor specification files - *.pspec
+
+
+ These files contain configuration information that is specific to a particular
+ processor variant.
+
+
+
+
+
+
+
+
+Modifying Specification Files
+
+
+ Changing any of the specification files described here is not recommended.
+ To make additions to either the compiler specification
+ or the processor specification files, see
+ “Specification Extensions”, which describes a safe and portable way
+ to add specific elements.
+
+
+
+
+
+
+
+ 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.
+
+
+
+ When Ghidra starts, it checks for changes to *.slaspec
+ and *.sinc files and will rebuild the corresponding
+ *.sla 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.
+
- Another source of options can be accessed by selecting the Code Browser menu
+ Options that are specific to the particular Program being analyzed are accessed by
+ selecting the Code Browser menu
Edit -> Options for <Program>
- and the picking the Decompiler tab. These “Program Options”
- are specific to the particular Program being analyzed.
+ Picking the Decompiler tab shows “Program Options”
+ that only affect the decompiler. Picking the “Specification Extensions” 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.
@@ -573,7 +576,8 @@
Program Options
- Changes to these options affect only the current Program being analyzed.
+ Changes to these options affect only the decompiler and only for
+ the current Program being analyzed.
@@ -595,6 +599,284 @@
+
+
+Specification Extensions
+
+
+ This tab displays elements from the Program's compiler specification and
+ processor specification and allows the user to add or remove
+ extensions, including prototype models, call-fixups, and
+ callother-fixups.
+
+
+ Every program has a core set of specification elements,
+ loaded from the “SLEIGH Specification Files”, 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.
+
+
+ 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.
+
+
+ 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:
+
+
+
+
+Extension Type - indicating the type of element
+
+Name - showing the formal name of the element
+
+Status - indicating whether the element is core or an extension
+
+
+
+ The core elements of the specification have a blank Status column, and any extension
+ is labeled either as "extension" or "override".
+
+
+
+Extension Types
+
+
+ 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 compiler specification file,
+ the processor specification file, or provided to Ghidra as an
+ import document.
+
+
+
+
prototype
+
+
+ This element is a “Prototype Model” 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 Function Editor Dialog.
+ See the documentation on “Function Prototypes” for how they affect decompilation.
+
+
+ The XML tag, <prototype> always has a name attribute
+ that defines the formal name of the prototype model, which must be unique across all models.
+
+ 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
+ “Function Prototypes”.
+
+
+ The <callfixup> tag has a name
+ attribute listing the formal name, which must be unique across all call-fixups.
+
+ 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 “User-defined P-code Operations - CALLOTHER”.
+
+
+ The <callotherfixup> tag has a
+ targetop attribute which lists the
+ name of the particular CALLOTHER operation it substitutes for.
+
+ 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.
+
+
+ With no changes pending, the column will show one of the three main values:
+
+
+
+
<blank>
+
+
+ A blank Status column indicates that the element is a core part of the
+ specification, originating from one of the specification files.
+ These elements cannot be changed or removed.
+
+
+
extension
+
+
+ Indicates that the element is a program specific extension that has been
+ added to the specification.
+
+
+
override
+
+
+ Indicates that the element, which must be a callotherfixup,
+ 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.
+
+
+
+
+
+
+
+ If the user has either imported additional extensions or selected an extensions for removal but
+ has not yet clicked the Apply button in the Options dialog, the Status column
+ may show one of the following values, indicating a pending change.
+
+
+
+
install
+
+
+ Indicates a new extension that will be installed.
+
+
+
remove
+
+
+ Indicates an extension that is about to be removed.
+
+
+
replace
+
+
+ Indicates a new extension that will replace a current
+ extension with the same name.
+
+
+
override pending
+
+
+ Indicates a new extension that will override a core element when
+ it is installed.
+
+
+
+
+
+
+
+
+
+Importing a New Extension
+
+
+ The Import button at the bottom of the
+ "Specification Extensions" pane allows the user to import one of the
+ three element types, prototype,
+ callfixup, or callotherfixup,
+ 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 Import button brings up a File Chooser dialog,
+ from which the user must select their prepared XML file. Once Ok 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.
+
+
+ The final change to the program, installing the new extension, will not happen until the
+ Apply button, at the bottom of the Options dialog, is clicked.
+
+
+ The XML file describing the extension must have one of the tags,
+ <prototype>, <callfixup>, or <callotherfixup>,
+ 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 “SLEIGH Specification Files”.
+
+
+ In the case of prototype and callfixup
+ elements, extensions cannot replace existing core elements, so the new extension must not
+ have a name that matches an existing core element. If a new callotherfixup
+ extension has a targetop that matches a core element, the extension is automatically treated as an override.
+
+
+ Existing extensions can be replaced simply by importing a new extension with the same name or targetop.
+
+
+
+
+Removing an Extension
+
+
+ The Remove 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 extension or override.
+ Core elements of the specification cannot be removed.
+ Clicking the Remove button brings up a confirmation dialog, and if
+ Ok is clicked, the selected extension is marked for removal. The Status of the row
+ changes to remove, reflecting this.
+
+
+ The final change to the program, removing the extension, will not happen until the
+ Apply button, at the bottom of the Options dialog, is clicked.
+
+
+ If a prototype or callfixup 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 default convention, which is always a core element.
+ A function with matching call-fixup is changed to have no call-fixup.
+