mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 19:42:36 +02:00
Program specific, user-defined, cspec extensions
Documentation for spec extensions Handle extensions with parse errors Export button for spec extensions Pop-up dialog for parse errors in user-defined specification extensions GP-653 corrected some minor issues and established new ProgramDB version make incremental initialization constructor for AddressSized private Make AddressSized fields private More adjustments to AddressSized Review fixes for BasicCompilerSpec Take restoreXml out of DataOrganization interface Remove restoreXml from BitFieldPacking interface More review fixes Prevent callotherfixup extension with non-existent target Suggested export name More documentation for SpecExtension Support for undo/redo with spec extensions Documentation for ConstructTpl Split out ProgramCompilerSpec and other changes for review Changes after next round of reviews
This commit is contained in:
parent
27fbe7278d
commit
a5d4ca3cab
108 changed files with 7997 additions and 1997 deletions
|
@ -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. **'
|
||||
"""
|
||||
|
|
|
@ -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|
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1218,6 +1218,26 @@ void Architecture::parseCompilerConfig(DocumentStorage &store)
|
|||
else if (elname == "inferptrbounds")
|
||||
parseInferPtrBounds(*iter);
|
||||
}
|
||||
|
||||
el = store.getTag("specextensions"); // Look for any user-defined configuration document
|
||||
if (el != (const Element *)0) {
|
||||
const List &userlist(el->getChildren());
|
||||
for(iter=userlist.begin();iter!=userlist.end();++iter) {
|
||||
const string &elname( (*iter)->getName() );
|
||||
if (elname == "prototype")
|
||||
parseProto(*iter);
|
||||
else if (elname == "callfixup") {
|
||||
pcodeinjectlib->restoreXmlInject(archid+" : compiler spec", (*iter)->getAttributeValue("name"),
|
||||
InjectPayload::CALLFIXUP_TYPE, *iter);
|
||||
}
|
||||
else if (elname == "callotherfixup") {
|
||||
userops.parseCallOtherFixup(*iter,this);
|
||||
}
|
||||
else if (elname == "global")
|
||||
globaltags.push_back(*iter);
|
||||
}
|
||||
}
|
||||
|
||||
// <global> tags instantiate the base symbol table
|
||||
// They need to know about all spaces, so it must come
|
||||
// after parsing of <stackpointer> and <spacebase>
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -293,6 +293,23 @@ int4 PcodeInjectLibrarySleigh::registerDynamicInject(InjectPayload *payload)
|
|||
return id;
|
||||
}
|
||||
|
||||
/// \brief Force a payload to be dynamic for debug purposes
|
||||
///
|
||||
/// Debug information may include inject information for payloads that aren't dynamic.
|
||||
/// We substitute a dynamic payload so that analysis uses the debug info to inject, rather
|
||||
/// than the hard-coded payload information.
|
||||
/// \param injectid is the id of the payload to treat dynamic
|
||||
/// \return the new dynamic payload object
|
||||
InjectPayloadDynamic *PcodeInjectLibrarySleigh::forceDebugDynamic(int4 injectid)
|
||||
|
||||
{
|
||||
InjectPayload *oldPayload = injection[injectid];
|
||||
InjectPayloadDynamic *newPayload = new InjectPayloadDynamic(glb,oldPayload->getName(),oldPayload->getType());
|
||||
delete oldPayload;
|
||||
injection[injectid] = newPayload;
|
||||
return newPayload;
|
||||
}
|
||||
|
||||
void PcodeInjectLibrarySleigh::parseInject(InjectPayload *payload)
|
||||
|
||||
{
|
||||
|
@ -399,9 +416,10 @@ void PcodeInjectLibrarySleigh::restoreDebug(const Element *el)
|
|||
s.unsetf(ios::dec | ios::hex | ios::oct);
|
||||
s >> type;
|
||||
int4 id = getPayloadId(type,name);
|
||||
InjectPayloadDynamic *payload = (InjectPayloadDynamic *)getPayload(id);
|
||||
if (payload->getSource() != "dynamic")
|
||||
throw LowlevelError("Mismatch with debug inject XML");
|
||||
InjectPayloadDynamic *payload = dynamic_cast<InjectPayloadDynamic *>(getPayload(id));
|
||||
if (payload == (InjectPayloadDynamic *)0) {
|
||||
payload = forceDebugDynamic(id);
|
||||
}
|
||||
payload->restoreEntry(subel);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -91,6 +91,7 @@ class PcodeInjectLibrarySleigh : public PcodeInjectLibrary {
|
|||
vector<OpBehavior *> inst;
|
||||
InjectContextSleigh contextCache;
|
||||
int4 registerDynamicInject(InjectPayload *payload);
|
||||
InjectPayloadDynamic *forceDebugDynamic(int4 injectid);
|
||||
void parseInject(InjectPayload *payload);
|
||||
protected:
|
||||
virtual int4 allocateInject(const string &sourceName,const string &name,int4 type);
|
||||
|
|
|
@ -216,10 +216,10 @@ void SegmentOp::restoreXml(const Element *el)
|
|||
throw LowlevelError("Bad segment pattern tag: "+subel->getName());
|
||||
}
|
||||
if (injectId < 0)
|
||||
throw LowlevelError("Missing <execute> child in <segmentop> tag");
|
||||
throw LowlevelError("Missing <pcode> child in <segmentop> tag");
|
||||
InjectPayload *payload = glb->pcodeinjectlib->getPayload(injectId);
|
||||
if (payload->sizeOutput() != 1)
|
||||
throw LowlevelError("<execute> child of <segmentop> tag must declare one <output>");
|
||||
throw LowlevelError("<pcode> child of <segmentop> tag must declare one <output>");
|
||||
if (payload->sizeInput() == 1) {
|
||||
innerinsize = payload->getInput(0).getSize();
|
||||
}
|
||||
|
@ -228,7 +228,7 @@ void SegmentOp::restoreXml(const Element *el)
|
|||
innerinsize = payload->getInput(1).getSize();
|
||||
}
|
||||
else
|
||||
throw LowlevelError("<execute> child of <segmentop> tag must declare one or two <input> tags");
|
||||
throw LowlevelError("<pcode> child of <segmentop> tag must declare one or two <input> tags");
|
||||
}
|
||||
|
||||
/// \param g is the Architecture owning this set of jump assist scripts
|
||||
|
|
|
@ -127,6 +127,12 @@ void XmlArchitecture::restoreXml(DocumentStorage &store)
|
|||
++iter;
|
||||
}
|
||||
}
|
||||
if (iter != list.end()) {
|
||||
if ((*iter)->getName() == "specextensions") {
|
||||
store.registerTag(*iter);
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
if (iter!=list.end()) {
|
||||
if ((*iter)->getName() == "coretypes") {
|
||||
store.registerTag(*iter);
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
<?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="/usr/share/sgml/docbook/xsl-stylesheets/html/chunk.xsl"/>
|
||||
<xsl:import href="http://docbook.sourceforge.net/release/xsl/current/html/chunk.xsl"/>
|
||||
|
||||
<xsl:param name="generate.toc">
|
||||
article/appendix nop
|
||||
|
|
|
@ -834,6 +834,33 @@
|
|||
</para>
|
||||
</sect3>
|
||||
|
||||
<sect3 id="ConceptCallother">
|
||||
<title>User-defined P-code Operations - CALLOTHER</title>
|
||||
<para>
|
||||
P-code allows for additional, processor specific, operations referred to
|
||||
as <emphasis>user-defined</emphasis> 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.
|
||||
</para>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<para>
|
||||
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
|
||||
<emphasis role="bold">Callother-Fixup</emphasis>, 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 <xref linkend="ExtensionOptions"/>)
|
||||
</para>
|
||||
</sect3>
|
||||
|
||||
<sect3 id="ConceptInternalFunctions">
|
||||
<title>Internal Decompiler Functions</title>
|
||||
<para>
|
||||
|
@ -1162,10 +1189,13 @@
|
|||
use of multiple models. Subsequently, each distinct model has a name like <code>__stdcall</code> or
|
||||
<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 <xref linkend="ExtensionOptions"/>.
|
||||
</para>
|
||||
<para>
|
||||
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:
|
||||
</para>
|
||||
<sect3 id="ConceptPrototypeStorage">
|
||||
<title>Incoming and Outgoing Storage Locations</title>
|
||||
|
@ -1211,6 +1241,138 @@
|
|||
</sect2>
|
||||
</section>
|
||||
|
||||
<section id="ConceptSpecification">
|
||||
<title>SLEIGH Specification Files</title>
|
||||
<para>
|
||||
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:
|
||||
<informalexample>
|
||||
<itemizedlist mark='bullet' spacing='compact'>
|
||||
<listitem>
|
||||
Disassemble machine instructions from the underlying bytes and
|
||||
</listitem>
|
||||
<listitem>
|
||||
Produce the raw p-code consumed by the decompiler and other analyzers.
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</informalexample>
|
||||
</para>
|
||||
<para>
|
||||
Specification files are selected based on the <emphasis>Language Id</emphasis>
|
||||
assigned to the Program at the time it is imported into Ghidra.
|
||||
(See <link xlink:href="help/topics/ImporterPlugin/importer.htm">Import Program</link>)
|
||||
<informalexample>
|
||||
<itemizedlist mark='none' spacing='compact'>
|
||||
<listitem><code>x86:LE:32:default:windows</code></listitem>
|
||||
<listitem><code>AARCH64:LE:64:default:v8A:default</code></listitem>
|
||||
<listitem><code>MIPS:BE:32:micro:default</code></listitem>
|
||||
</itemizedlist>
|
||||
</informalexample>
|
||||
A <emphasis role="bold">Language Id</emphasis> is a label with these 5 formal fields, separated
|
||||
by a ':' character:
|
||||
<informalexample>
|
||||
<itemizedlist spacing='compact'>
|
||||
<listitem>Processor family</listitem>
|
||||
<listitem>Endianess</listitem>
|
||||
<listitem>Size of the address bus</listitem>
|
||||
<listitem>Process variant</listitem>
|
||||
<listitem>Compiler producing the Program</listitem>
|
||||
</itemizedlist>
|
||||
</informalexample>
|
||||
A field with the value 'default' indicates either the preferred processor variant or the preferred compiler.
|
||||
</para>
|
||||
<para>
|
||||
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
|
||||
<informalexample>
|
||||
<code><Root>/Ghidra/Processors/<Family>/data/languages</code>
|
||||
</informalexample>
|
||||
where <code><Root></code> represents the root directory of the Ghidra installation and
|
||||
<code><Family></code> is the processor family.
|
||||
</para>
|
||||
<para>
|
||||
There are several types of specification files that are distinguishable by their suffix.
|
||||
These include:
|
||||
<informalexample>
|
||||
<variablelist>
|
||||
<?dbfo list-presentation="blocks"?>
|
||||
<varlistentry>
|
||||
<term><emphasis role="bold">SLEIGH files</emphasis> - *.slaspec or *.sinc</term>
|
||||
<listitem>
|
||||
<para>
|
||||
These are the human readable SLEIGH language files. A single specification is
|
||||
rooted in one of the <code>*.slaspec</code> files, which may recursively include
|
||||
one or more <code>*.sinc</code> files. The format of these files is described
|
||||
in the document "SLEIGH: A Language for Rapid Processor Specification".
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><emphasis role="bold">Compiled SLEIGH files</emphasis> - *.sla</term>
|
||||
<listitem>
|
||||
<para>
|
||||
This is a compiled form of a single SLEIGH specification. It is produced
|
||||
automatically by Ghidra from the corresponding <code>*.slaspec</code>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><emphasis role="bold">Compiler specification files</emphasis> - *.cspec</term>
|
||||
<listitem>
|
||||
<para>
|
||||
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:
|
||||
</para>
|
||||
<para>
|
||||
<itemizedlist mark='none' spacing='compact'>
|
||||
<listitem><prototype> - describing a specific calling convention</listitem>
|
||||
<listitem><callfixup> - describing a Call-fixup</listitem>
|
||||
<listitem><callotherfixup> - describing a Callother-fixup</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><emphasis role="bold">Processor specification files</emphasis> - *.pspec</term>
|
||||
<listitem>
|
||||
<para>
|
||||
These files contain configuration information that is specific to a particular
|
||||
processor variant.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</informalexample>
|
||||
</para>
|
||||
<sect2 id="ConceptModifySpec">
|
||||
<title>Modifying Specification Files</title>
|
||||
<para>
|
||||
Changing any of the specification files described here is not recommended.
|
||||
To make additions to either the <emphasis>compiler specification</emphasis>
|
||||
or the <emphasis>processor specification</emphasis> files, see
|
||||
<xref linkend="ExtensionOptions"/>, which describes a safe and portable way
|
||||
to add specific elements.
|
||||
</para>
|
||||
<warning>
|
||||
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.
|
||||
</warning>
|
||||
<para>
|
||||
When Ghidra starts, it checks for changes to <code>*.slaspec</code>
|
||||
and <code>*.sinc</code> files and will rebuild the corresponding
|
||||
<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.
|
||||
</para>
|
||||
</sect2>
|
||||
</section>
|
||||
|
||||
</chapter>
|
||||
|
||||
<chapter id="DecompilerAnnotations">
|
||||
|
@ -2085,7 +2247,8 @@
|
|||
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 <xref linkend="ConceptPrototypeModel"/> that describes how storage
|
||||
locations are selected for individual parameters along with other information about how the compiler treats
|
||||
the function.
|
||||
the function. Available models are determined by the processor and compiler, but can be extended by the user.
|
||||
See <xref linkend="ExtensionOptions"/>.
|
||||
</para>
|
||||
<para>
|
||||
In the absence of parameter and return value annotations, the decompiler will use the prototype model as
|
||||
|
@ -2152,7 +2315,8 @@
|
|||
</para>
|
||||
<para>
|
||||
Call-fixups are specified by name. The name and associated p-code chunk are typically defined in the
|
||||
<emphasis>compiler specification</emphasis> for the Program.
|
||||
<emphasis>compiler specification</emphasis> for the Program. Users can extend the available set
|
||||
of call-fixups. See <xref linkend="ExtensionOptions"/>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
@ -2453,12 +2617,15 @@
|
|||
</informalexample>
|
||||
</para>
|
||||
<para>
|
||||
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
|
||||
<informalexample>
|
||||
<emphasis role="bold">Edit -> Options for <Program></emphasis>
|
||||
</informalexample>
|
||||
and the picking the <emphasis>Decompiler</emphasis> tab. These <xref linkend="ProgramOptions"/>
|
||||
are specific to the particular Program being analyzed.
|
||||
Picking the <emphasis>Decompiler</emphasis> tab shows <xref linkend="ProgramOptions"/>
|
||||
that only affect the decompiler. Picking the <xref linkend="ExtensionOptions"/> 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.
|
||||
</para>
|
||||
</simplesect>
|
||||
<section id="GeneralOptions">
|
||||
|
@ -2961,7 +3128,8 @@
|
|||
<section id="ProgramOptions">
|
||||
<title>Program Options</title>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<para>
|
||||
<informalexample>
|
||||
|
@ -2982,6 +3150,280 @@
|
|||
</informalexample>
|
||||
</para>
|
||||
</section>
|
||||
<section id="ExtensionOptions">
|
||||
<title>Specification Extensions</title>
|
||||
<para>
|
||||
This tab displays elements from the Program's <emphasis>compiler specification</emphasis> and
|
||||
<emphasis>processor specification</emphasis> and allows the user to add or remove
|
||||
<emphasis role="bold">extensions</emphasis>, including prototype models, call-fixups, and
|
||||
callother-fixups.
|
||||
</para>
|
||||
<para>
|
||||
Every program has a <emphasis>core</emphasis> set of specification elements,
|
||||
loaded from the <xref linkend="ConceptSpecification"/>, 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.
|
||||
</para>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<para>
|
||||
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:
|
||||
<informalexample>
|
||||
<itemizedlist mark='none' spacing='compact'>
|
||||
<listitem><emphasis role="bold">Extension Type</emphasis> - indicating the type of element</listitem>
|
||||
<listitem><emphasis role="bold">Name</emphasis> - showing the formal name of the element</listitem>
|
||||
<listitem><emphasis role="bold">Status</emphasis> - indicating whether the element is core or an extension</listitem>
|
||||
</itemizedlist>
|
||||
</informalexample>
|
||||
The core elements of the specification have a blank Status column, and any extension
|
||||
is labeled either as "extension" or "override".
|
||||
</para>
|
||||
<sect2 id="ExtendTypes">
|
||||
<title>Extension Types</title>
|
||||
<para>
|
||||
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 <emphasis>compiler specification</emphasis> file,
|
||||
the <emphasis>processor specification</emphasis> file, or provided to Ghidra as an
|
||||
import document.
|
||||
<informalexample>
|
||||
<variablelist>
|
||||
<?dbfo list-presentation="blocks"?>
|
||||
<varlistentry>
|
||||
<term><emphasis role="bold">prototype</emphasis></term>
|
||||
<listitem>
|
||||
<para>
|
||||
This element is a <xref linkend="ConceptPrototypeModel"/> 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 <link xlink:href="help/topics/FunctionPlugin/Variables.htm#Edit_Function">Function Editor Dialog</link>.
|
||||
See the documentation on <xref linkend="AnnotePrototype"/> for how they affect decompilation.
|
||||
</para>
|
||||
<para>
|
||||
The XML tag, <code><prototype></code> always has a <emphasis role="bold">name</emphasis> attribute
|
||||
that defines the formal name of the prototype model, which must be unique across all models.
|
||||
<programlisting>
|
||||
<![CDATA[<prototype name="__stdcall" extrapop="unknown" stackshift="4">
|
||||
<input>
|
||||
<pentry minsize="1" maxsize="500" align="4">
|
||||
<addr offset="4" space="stack"/>
|
||||
</pentry>
|
||||
</input>
|
||||
<output>
|
||||
...]]>
|
||||
</programlisting>
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><emphasis role="bold">callfixup</emphasis></term>
|
||||
<listitem>
|
||||
<para>
|
||||
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
|
||||
<xref linkend="AnnotePrototype"/>.
|
||||
</para>
|
||||
<para>
|
||||
The <code><callfixup></code> tag has a <emphasis role="bold">name</emphasis>
|
||||
attribute listing the formal name, which must be unique across all call-fixups.
|
||||
<programlisting>
|
||||
<![CDATA[<callfixup name="EH_prolog3">
|
||||
<pcode>
|
||||
<body><![CDATA<
|
||||
EBP = ESP + 4;
|
||||
tmp = * EBP;
|
||||
ESP = ESP - tmp;
|
||||
ESP = ESP - 24;
|
||||
]]>]]><![CDATA[</body>
|
||||
</pcode>
|
||||
</callfixup>]]>
|
||||
</programlisting>
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><emphasis role="bold">callotherfixup</emphasis></term>
|
||||
<listitem>
|
||||
<para>
|
||||
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 <xref linkend="ConceptCallother"/>.
|
||||
</para>
|
||||
<para>
|
||||
The <code><callotherfixup></code> tag has a
|
||||
<emphasis role="bold">targetop</emphasis> attribute which lists the
|
||||
name of the particular CALLOTHER operation it substitutes for.
|
||||
<programlisting>
|
||||
<![CDATA[<callotherfixup targetop="dynamicPush">
|
||||
<pcode>
|
||||
<input name="amount"/>
|
||||
<body><![CDATA[
|
||||
RSP = RSP + amount;
|
||||
]]>]]><![CDATA[</body>
|
||||
</pcode>
|
||||
</callotherfixup>]]>
|
||||
</programlisting>
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</informalexample>
|
||||
</para>
|
||||
</sect2>
|
||||
<sect2 id="ExtendStatus">
|
||||
<title>Status</title>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<para>
|
||||
With no changes pending, the column will show one of the three main values:
|
||||
<informalexample>
|
||||
<variablelist>
|
||||
<?dbfo list-presentation="blocks"?>
|
||||
<varlistentry>
|
||||
<term><emphasis><blank></emphasis></term>
|
||||
<listitem>
|
||||
<para>
|
||||
A blank Status column indicates that the element is a core part of the
|
||||
specification, originating from one of the <emphasis>specification files</emphasis>.
|
||||
These elements cannot be changed or removed.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><emphasis role="bold">extension</emphasis></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Indicates that the element is a program specific extension that has been
|
||||
added to the specification.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><emphasis role="bold">override</emphasis></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Indicates that the element, which must be a <emphasis role="bold">callotherfixup</emphasis>,
|
||||
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.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</informalexample>
|
||||
</para>
|
||||
<para>
|
||||
If the user has either imported additional extensions or selected an extension for removal but
|
||||
has not yet clicked the <emphasis>Apply</emphasis> button in the Options dialog, the Status column
|
||||
may show one of the following values, indicating a pending change.
|
||||
<informalexample>
|
||||
<variablelist>
|
||||
<?dbfo list-presentation="blocks"?>
|
||||
<varlistentry>
|
||||
<term><emphasis role="bold">install</emphasis></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Indicates a new extension that will be installed.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><emphasis role="bold">remove</emphasis></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Indicates an extension that is about to be removed.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><emphasis role="bold">replace</emphasis></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Indicates a new extension that will replace a current
|
||||
extension with the same name.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><emphasis role="bold">override pending</emphasis></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Indicates a new extension that will override a core element when
|
||||
it is installed.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</informalexample>
|
||||
</para>
|
||||
</sect2>
|
||||
<sect2 id="ExtendImport">
|
||||
<title>Importing a New Extension</title>
|
||||
<para>
|
||||
The <emphasis>Import</emphasis> button at the bottom of the
|
||||
"Specification Extensions" pane allows the user to import one of the
|
||||
three element types, <emphasis role="bold">prototype</emphasis>,
|
||||
<emphasis role="bold">callfixup</emphasis>, or <emphasis role="bold">callotherfixup</emphasis>,
|
||||
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 <emphasis>Import</emphasis> button brings up a File Chooser dialog,
|
||||
from which the user must select their prepared XML file. Once <emphasis>Ok</emphasis> 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.
|
||||
</para>
|
||||
<para>
|
||||
The final change to the program, installing the new extension, will not happen until the
|
||||
<emphasis>Apply</emphasis> button, at the bottom of the Options dialog, is clicked.
|
||||
</para>
|
||||
<para>
|
||||
The XML file describing the extension <emphasis>must</emphasis> have one of the tags,
|
||||
<code><prototype></code>, <code><callfixup></code>, or <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 <xref linkend="ConceptSpecification"/>.
|
||||
</para>
|
||||
<para>
|
||||
In the case of <emphasis role="bold">prototype</emphasis> and <emphasis role="bold">callfixup</emphasis>
|
||||
elements, extensions cannot replace existing core elements, so the new extension <emphasis>must not</emphasis>
|
||||
have a name that matches an existing core element. If a new <emphasis role="bold">callotherfixup</emphasis>
|
||||
extension has a targetop that matches a core element, the extension is automatically treated as an override.
|
||||
</para>
|
||||
<para>
|
||||
Existing extensions can be replaced simply by importing a new extension with the same name or targetop.
|
||||
</para>
|
||||
</sect2>
|
||||
<sect2 id="ExtendRemove">
|
||||
<title>Removing an Extension</title>
|
||||
<para>
|
||||
The <emphasis>Remove</emphasis> 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 <emphasis role="bold">extension</emphasis> or <emphasis role="bold">override</emphasis>.
|
||||
Core elements of the specification cannot be removed.
|
||||
Clicking the <emphasis>Remove</emphasis> button brings up a confirmation dialog, and if
|
||||
<emphasis>Ok</emphasis> is clicked, the selected extension is marked for removal. The Status of the row
|
||||
changes to <emphasis role="bold">remove</emphasis>, reflecting this.
|
||||
</para>
|
||||
<para>
|
||||
The final change to the program, removing the extension, will not happen until the
|
||||
<emphasis>Apply</emphasis> button, at the bottom of the Options dialog, is clicked.
|
||||
</para>
|
||||
<para>
|
||||
If a <emphasis role="bold">prototype</emphasis> or <emphasis role="bold">callfixup</emphasis> 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 <emphasis>default</emphasis> convention, which is always a core element.
|
||||
A function with matching call-fixup is changed to have no call-fixup.
|
||||
</para>
|
||||
</sect2>
|
||||
</section>
|
||||
|
||||
</chapter>
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<xsl:stylesheet
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
|
||||
|
||||
<xsl:import href="/usr/share/sgml/docbook/xsl-stylesheets/html/chunk.xsl"/>
|
||||
<xsl:import href="http://docbook.sourceforge.net/release/xsl/current/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="/usr/share/sgml/docbook/xsl-stylesheets/fo/docbook.xsl"/>
|
||||
<xsl:import href="http://docbook.sourceforge.net/release/xsl/current/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="'./images/'"/>
|
||||
<xsl:param name="admon.graphics.path" select="'../../../build/images'"/>
|
||||
|
||||
</xsl:stylesheet>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<xsl:stylesheet
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
|
||||
|
||||
<xsl:import href="/usr/share/sgml/docbook/xsl-stylesheets/html/docbook.xsl"/>
|
||||
<xsl:import href="http://docbook.sourceforge.net/release/xsl/current/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="/usr/share/sgml/docbook/xsl-stylesheets/html/chunk.xsl"/>
|
||||
<xsl:import href="http://docbook.sourceforge.net/release/xsl/current/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="/usr/share/sgml/docbook/xsl-stylesheets/fo/docbook.xsl"/>
|
||||
<xsl:import href="http://docbook.sourceforge.net/release/xsl/current/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="/usr/share/sgml/docbook/xsl-stylesheets/html/chunk.xsl"/>
|
||||
<xsl:import href="http://docbook.sourceforge.net/release/xsl/current/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="/usr/share/sgml/docbook/xsl-stylesheets/fo/docbook.xsl"/>
|
||||
<xsl:import href="http://docbook.sourceforge.net/release/xsl/current/fo/docbook.xsl"/>
|
||||
|
||||
<xsl:include href="sleigh_common.xsl" />
|
||||
|
||||
|
|
|
@ -62,6 +62,7 @@
|
|||
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"
|
||||
|
@ -83,6 +84,7 @@
|
|||
<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"
|
||||
|
@ -91,9 +93,10 @@
|
|||
<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="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 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>
|
||||
</tocdef>
|
||||
</tocref>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<title>Program Annotations Affecting the Decompiler</title>
|
||||
<link rel="stylesheet" type="text/css" href="../../shared/Frontpage.css">
|
||||
<link rel="stylesheet" type="text/css" href="../../shared/languages.css">
|
||||
<meta name="generator" content="DocBook XSL Stylesheets V1.78.1">
|
||||
<meta name="generator" content="DocBook XSL Stylesheets V1.79.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,7 +983,8 @@
|
|||
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.
|
||||
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>.
|
||||
</p>
|
||||
<p>
|
||||
In the absence of parameter and return value annotations, the decompiler will use the prototype model as
|
||||
|
@ -1042,7 +1043,8 @@
|
|||
</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.
|
||||
<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>.
|
||||
</p>
|
||||
</dd>
|
||||
</dl></div>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<title>Decompiler Concepts</title>
|
||||
<link rel="stylesheet" type="text/css" href="../../shared/Frontpage.css">
|
||||
<link rel="stylesheet" type="text/css" href="../../shared/languages.css">
|
||||
<meta name="generator" content="DocBook XSL Stylesheets V1.78.1">
|
||||
<meta name="generator" content="DocBook XSL Stylesheets V1.79.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">
|
||||
<div class="table-contents"><table width="90%" frame="box" rules="all" id="ops.htmltable">
|
||||
|
||||
<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">
|
||||
<a name="ref.htmltable"></a><table width="90%" frame="box" rules="rows" id="ref.htmltable">
|
||||
<col width="25%">
|
||||
<col width="25%">
|
||||
<col width="50%">
|
||||
|
@ -725,6 +725,35 @@
|
|||
|
||||
<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>
|
||||
|
@ -1052,10 +1081,13 @@
|
|||
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.
|
||||
the sub-concepts of the model may be relevant to reverse engineers. Concepts that a prototype
|
||||
model encapsulates include:
|
||||
</p>
|
||||
<div class="sect3">
|
||||
<div class="titlepage"><div><div><h4 class="title">
|
||||
|
@ -1107,5 +1139,150 @@
|
|||
</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>
|
||||
|
|
|
@ -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.78.1">
|
||||
<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
|
||||
<link rel="home" href="Decompiler.html" title="Decompiler">
|
||||
<link rel="up" href="Decompiler.html" title="Decompiler">
|
||||
<link rel="prev" href="Decompiler.html" title="Decompiler">
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<title>Decompiler Options</title>
|
||||
<link rel="stylesheet" type="text/css" href="../../shared/Frontpage.css">
|
||||
<link rel="stylesheet" type="text/css" href="../../shared/languages.css">
|
||||
<meta name="generator" content="DocBook XSL Stylesheets V1.78.1">
|
||||
<meta name="generator" content="DocBook XSL Stylesheets V1.79.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,14 +42,17 @@
|
|||
<p>
|
||||
</p>
|
||||
<p>
|
||||
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
|
||||
</p>
|
||||
<div class="informalexample">
|
||||
<span class="bold"><strong>Edit -> Options for <Program></strong></span>
|
||||
</div>
|
||||
<p>
|
||||
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.
|
||||
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.
|
||||
</p>
|
||||
</div>
|
||||
<div class="section">
|
||||
|
@ -573,7 +576,8 @@
|
|||
<a name="ProgramOptions"></a>Program Options</h2></div></div></div>
|
||||
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
<p>
|
||||
</p>
|
||||
|
@ -595,6 +599,284 @@
|
|||
<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>
|
||||
|
|
|
@ -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.78.1">
|
||||
<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
|
||||
<link rel="home" href="Decompiler.html" title="Decompiler">
|
||||
<link rel="up" href="Decompiler.html" title="Decompiler">
|
||||
<link rel="prev" href="DecompilerOptions.html" title="Decompiler Options">
|
||||
|
|
|
@ -222,7 +222,7 @@ public class DecompInterface {
|
|||
(SleighLanguageDescription) pcodelanguage.getLanguageDescription();
|
||||
ResourceFile pspecfile = sleighdescription.getSpecFile();
|
||||
String pspecxml = fileToString(pspecfile);
|
||||
String cspecxml = compilerSpec.getCompilerSpecString();
|
||||
String cspecxml = compilerSpec.getXMLString();
|
||||
|
||||
decompCallback.setNativeMessage(null);
|
||||
decompProcess.registerProgram(decompCallback, pspecxml, cspecxml, tspec, coretypes);
|
||||
|
@ -232,8 +232,9 @@ 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");
|
||||
}
|
||||
}
|
||||
|
@ -241,14 +242,16 @@ 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");
|
||||
}
|
||||
}
|
||||
|
@ -258,14 +261,16 @@ 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");
|
||||
}
|
||||
}
|
||||
|
@ -409,8 +414,9 @@ 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
|
||||
|
@ -446,8 +452,9 @@ 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
|
||||
|
@ -484,8 +491,9 @@ 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
|
||||
|
@ -521,8 +529,9 @@ 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
|
||||
|
@ -551,8 +560,9 @@ 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
|
||||
|
@ -588,8 +598,9 @@ 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
|
||||
|
@ -707,9 +718,10 @@ public class DecompInterface {
|
|||
debug.setFunction(func);
|
||||
}
|
||||
decompCallback.setFunction(func, funcEntry, debug);
|
||||
String addrstring = Varnode.buildXMLAddress(funcEntry);
|
||||
StringBuilder addrBuf = new StringBuilder();
|
||||
AddressXML.buildXML(addrBuf, funcEntry);
|
||||
verifyProcess();
|
||||
res = decompProcess.sendCommand1ParamTimeout("decompileAt", addrstring.toString(),
|
||||
res = decompProcess.sendCommand1ParamTimeout("decompileAt", addrBuf.toString(),
|
||||
timeoutSecs);
|
||||
decompileMessage = decompCallback.getNativeMessage();
|
||||
}
|
||||
|
|
|
@ -55,6 +55,7 @@ import ghidra.util.xml.XmlUtilities;
|
|||
public class DecompileCallback {
|
||||
|
||||
public final static int MAX_SYMBOL_COUNT = 16;
|
||||
|
||||
/**
|
||||
* Data returned for a query about strings
|
||||
*/
|
||||
|
@ -70,6 +71,7 @@ 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;
|
||||
|
@ -125,6 +127,8 @@ 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);
|
||||
|
@ -153,19 +157,6 @@ 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();
|
||||
|
@ -182,9 +173,11 @@ public class DecompileCallback {
|
|||
|
||||
public byte[] getBytes(String addrxml) {
|
||||
try {
|
||||
int size = readXMLSize(addrxml);
|
||||
Address addr;
|
||||
addr = Varnode.readXMLAddress(addrxml, addrfactory, funcEntry.getAddressSpace());
|
||||
Address addr = AddressXML.readXML(addrxml, addrfactory);
|
||||
int size = AddressXML.readXMLSize(addrxml);
|
||||
if (overlaySpace != null) {
|
||||
addr = overlaySpace.getOverlayAddress(addr);
|
||||
}
|
||||
if (addr == Address.NO_ADDRESS) {
|
||||
throw new PcodeXMLException("Address does not physically map");
|
||||
}
|
||||
|
@ -230,7 +223,10 @@ public class DecompileCallback {
|
|||
Address addr;
|
||||
int flags;
|
||||
try {
|
||||
addr = Varnode.readXMLAddress(addrstring, addrfactory, funcEntry.getAddressSpace());
|
||||
addr = AddressXML.readXML(addrstring, addrfactory);
|
||||
if (overlaySpace != null) {
|
||||
addr = overlaySpace.getOverlayAddress(addr);
|
||||
}
|
||||
}
|
||||
catch (PcodeXMLException e) {
|
||||
Msg.error(this, "Decompiling " + funcEntry + ": " + e.getMessage());
|
||||
|
@ -270,7 +266,10 @@ public class DecompileCallback {
|
|||
public PackedBytes getPcodePacked(String addrstring) {
|
||||
Address addr = null;
|
||||
try {
|
||||
addr = Varnode.readXMLAddress(addrstring, addrfactory, funcEntry.getAddressSpace());
|
||||
addr = AddressXML.readXML(addrstring, addrfactory);
|
||||
if (overlaySpace != null) {
|
||||
addr = overlaySpace.getOverlayAddress(addr);
|
||||
}
|
||||
}
|
||||
catch (PcodeXMLException e) {
|
||||
Msg.error(this, "Decompiling " + funcEntry + ": " + e.getMessage());
|
||||
|
@ -293,8 +292,9 @@ 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, program, context);
|
||||
InjectPayload payload = snippetLibrary.getPayload(type, nm);
|
||||
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,7 +487,10 @@ public class DecompileCallback {
|
|||
public String getSymbol(String addrstring) { // Return first symbol name at this address
|
||||
Address addr;
|
||||
try {
|
||||
addr = Varnode.readXMLAddress(addrstring, addrfactory, funcEntry.getAddressSpace());
|
||||
addr = AddressXML.readXML(addrstring, addrfactory);
|
||||
if (overlaySpace != null) {
|
||||
addr = overlaySpace.getOverlayAddress(addr);
|
||||
}
|
||||
}
|
||||
catch (PcodeXMLException e) {
|
||||
Msg.error(this, "Decompiling " + funcEntry + ": " + e.getMessage());
|
||||
|
@ -627,8 +630,8 @@ public class DecompileCallback {
|
|||
buf.append("<comment");
|
||||
SpecXmlUtils.encodeStringAttribute(buf, "type", "header");
|
||||
buf.append(">\n");
|
||||
buf.append(Varnode.buildXMLAddress(addr));
|
||||
buf.append(Varnode.buildXMLAddress(addr));
|
||||
AddressXML.buildXML(buf, addr);
|
||||
AddressXML.buildXML(buf, addr);
|
||||
buf.append("\n<text>");
|
||||
SpecXmlUtils.xmlEscape(buf, text);
|
||||
buf.append("</text>\n");
|
||||
|
@ -680,8 +683,8 @@ public class DecompileCallback {
|
|||
buf.append("<comment");
|
||||
SpecXmlUtils.encodeStringAttribute(buf, "type", typename);
|
||||
buf.append(">\n");
|
||||
buf.append(Varnode.buildXMLAddress(addr));
|
||||
buf.append(Varnode.buildXMLAddress(commaddr));
|
||||
AddressXML.buildXML(buf, addr);
|
||||
AddressXML.buildXML(buf, commaddr);
|
||||
buf.append("\n<text>");
|
||||
SpecXmlUtils.xmlEscape(buf, text);
|
||||
buf.append("</text>\n");
|
||||
|
@ -701,7 +704,10 @@ public class DecompileCallback {
|
|||
public String getMappedSymbolsXML(String addrstring) { // Return XML describing data or functions at addr
|
||||
Address addr;
|
||||
try {
|
||||
addr = Varnode.readXMLAddress(addrstring, addrfactory, funcEntry.getAddressSpace());
|
||||
addr = AddressXML.readXML(addrstring, addrfactory);
|
||||
if (overlaySpace != null) {
|
||||
addr = overlaySpace.getOverlayAddress(addr);
|
||||
}
|
||||
if (addr == Address.NO_ADDRESS) {
|
||||
// Unknown spaces may result from "spacebase" registers defined in cspec
|
||||
return null;
|
||||
|
@ -743,7 +749,10 @@ public class DecompileCallback {
|
|||
public String getExternalRefXML(String addrstring) { // Return any external reference at addr
|
||||
Address addr;
|
||||
try {
|
||||
addr = Varnode.readXMLAddress(addrstring, addrfactory, funcEntry.getAddressSpace());
|
||||
addr = AddressXML.readXML(addrstring, addrfactory);
|
||||
if (overlaySpace != null) {
|
||||
addr = overlaySpace.getOverlayAddress(addr);
|
||||
}
|
||||
}
|
||||
catch (PcodeXMLException e) {
|
||||
Msg.error(this, "Decompiling " + funcEntry + ": " + e.getMessage());
|
||||
|
@ -792,6 +801,7 @@ public class DecompileCallback {
|
|||
Namespace namespc = funcSymbol.getNamespace();
|
||||
if (debug != null) {
|
||||
debug.getFNTypes(hfunc);
|
||||
debug.addPossiblePrototypeExtension(func);
|
||||
}
|
||||
return buildResult(funcSymbol, namespc);
|
||||
}
|
||||
|
@ -829,8 +839,8 @@ public class DecompileCallback {
|
|||
public String getRegisterName(String addrstring) {
|
||||
try {
|
||||
|
||||
Address addr = Varnode.readXMLAddress(addrstring, addrfactory, null);
|
||||
int size = readXMLSize(addrstring);
|
||||
Address addr = AddressXML.readXML(addrstring, addrfactory);
|
||||
int size = AddressXML.readXMLSize(addrstring);
|
||||
Register reg = pcodelanguage.getRegister(addr, size);
|
||||
if (reg == null) {
|
||||
return null;
|
||||
|
@ -847,7 +857,10 @@ public class DecompileCallback {
|
|||
public String getTrackedRegisters(String addrstring) {
|
||||
Address addr;
|
||||
try {
|
||||
addr = Varnode.readXMLAddress(addrstring, addrfactory, funcEntry.getAddressSpace());
|
||||
addr = AddressXML.readXML(addrstring, addrfactory);
|
||||
if (overlaySpace != null) {
|
||||
addr = overlaySpace.getOverlayAddress(addr);
|
||||
}
|
||||
}
|
||||
catch (PcodeXMLException e) {
|
||||
Msg.error(this, "Decompiling " + funcEntry + ": " + e.getMessage());
|
||||
|
@ -858,7 +871,7 @@ public class DecompileCallback {
|
|||
StringBuilder stringBuf = new StringBuilder();
|
||||
|
||||
stringBuf.append("<tracked_pointset");
|
||||
Varnode.appendSpaceOffset(stringBuf, addr);
|
||||
AddressXML.appendAttributes(stringBuf, addr);
|
||||
stringBuf.append(">\n");
|
||||
for (Register reg : context.getRegisters()) {
|
||||
if (reg.isProcessorContext()) {
|
||||
|
@ -1020,8 +1033,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,
|
||||
|
@ -1031,6 +1044,7 @@ public class DecompileCallback {
|
|||
Namespace namespc = functionSymbol.getNamespace();
|
||||
if (debug != null) {
|
||||
debug.getFNTypes(hfunc);
|
||||
debug.addPossiblePrototypeExtension(func);
|
||||
}
|
||||
return buildResult(functionSymbol, namespc);
|
||||
}
|
||||
|
@ -1304,8 +1318,11 @@ public class DecompileCallback {
|
|||
Address addr;
|
||||
int maxChars;
|
||||
try {
|
||||
maxChars = readXMLSize(addrString);
|
||||
addr = Varnode.readXMLAddress(addrString, addrfactory, funcEntry.getAddressSpace());
|
||||
addr = AddressXML.readXML(addrString, addrfactory);
|
||||
maxChars = AddressXML.readXMLSize(addrString);
|
||||
if (overlaySpace != null) {
|
||||
addr = overlaySpace.getOverlayAddress(addr);
|
||||
}
|
||||
if (addr == Address.NO_ADDRESS) {
|
||||
throw new PcodeXMLException("Address does not physically map");
|
||||
}
|
||||
|
|
|
@ -47,6 +47,7 @@ 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
|
||||
|
@ -108,16 +109,17 @@ public class DecompileDebug {
|
|||
public DecompileDebug(File debugf) {
|
||||
func = null;
|
||||
debugFile = debugf;
|
||||
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>();
|
||||
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<>();
|
||||
contextRegister = null;
|
||||
comments = null;
|
||||
globalnamespace = null;
|
||||
|
@ -158,6 +160,7 @@ 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);
|
||||
|
@ -178,7 +181,6 @@ public class DecompileDebug {
|
|||
debugStream.close();
|
||||
}
|
||||
catch (Exception e) {
|
||||
// TODO Auto-generated catch block
|
||||
Msg.error(this, "Unexpected Exception: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
@ -224,24 +226,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) {
|
||||
|
@ -290,9 +292,9 @@ public class DecompileDebug {
|
|||
StringBuilder buf = new StringBuilder();
|
||||
buf.append("<stringmanage>\n");
|
||||
for (Map.Entry<Address, StringData> entry : stringmap.entrySet()) {
|
||||
buf.append("<string>\n<addr");
|
||||
Varnode.appendSpaceOffset(buf, entry.getKey());
|
||||
buf.append("/>\n<bytes");
|
||||
buf.append("<string>\n");
|
||||
AddressXML.buildXML(buf, entry.getKey());
|
||||
buf.append("\n<bytes");
|
||||
SpecXmlUtils.encodeBooleanAttribute(buf, "trunc", entry.getValue().isTruncated);
|
||||
buf.append(">\n ");
|
||||
int count = 0;
|
||||
|
@ -339,12 +341,15 @@ 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());
|
||||
|
@ -365,7 +370,7 @@ public class DecompileDebug {
|
|||
if (!(lang instanceof SleighLanguage)) {
|
||||
return null;
|
||||
}
|
||||
ArrayList<ContextSymbol> res = new ArrayList<ContextSymbol>();
|
||||
ArrayList<ContextSymbol> res = new ArrayList<>();
|
||||
ghidra.app.plugin.processors.sleigh.symbol.Symbol[] list =
|
||||
((SleighLanguage) lang).getSymbolTable().getSymbolList();
|
||||
for (Symbol element : list) {
|
||||
|
@ -426,8 +431,7 @@ public class DecompileDebug {
|
|||
break;
|
||||
}
|
||||
}
|
||||
if (i == buf.length)
|
||||
{
|
||||
if (i == buf.length) {
|
||||
continue; // If all data is identical, then changepoint is not necessary
|
||||
}
|
||||
}
|
||||
|
@ -439,7 +443,7 @@ public class DecompileDebug {
|
|||
}
|
||||
|
||||
stringBuf.append("<context_pointset");
|
||||
Varnode.appendSpaceOffset(stringBuf, addr);
|
||||
AddressXML.appendAttributes(stringBuf, addr);
|
||||
stringBuf.append(">\n");
|
||||
for (ContextSymbol sym : ctxsymbols) {
|
||||
int sbit = sym.getInternalLow();
|
||||
|
@ -466,7 +470,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());
|
||||
|
@ -492,8 +496,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 {
|
||||
|
@ -508,11 +512,11 @@ public class DecompileDebug {
|
|||
}
|
||||
|
||||
private ArrayList<Namespace> orderNamespaces() {
|
||||
TreeMap<Long, Namespace> namespaceMap = new TreeMap<Long, Namespace>();
|
||||
TreeMap<Long, Namespace> namespaceMap = new TreeMap<>();
|
||||
for (Namespace namespace : dbscope) {
|
||||
namespaceMap.put(namespace.getID(), namespace);
|
||||
}
|
||||
ArrayList<Namespace> res = new ArrayList<Namespace>();
|
||||
ArrayList<Namespace> res = new ArrayList<>();
|
||||
while (!namespaceMap.isEmpty()) {
|
||||
Entry<Long, Namespace> entry = namespaceMap.firstEntry();
|
||||
Long curKey = entry.getKey();
|
||||
|
@ -592,6 +596,31 @@ 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());
|
||||
}
|
||||
|
@ -666,11 +695,9 @@ public class DecompileDebug {
|
|||
buf.append(" <labelsym");
|
||||
SpecXmlUtils.xmlEscapeAttribute(buf, "name", name);
|
||||
SpecXmlUtils.encodeUnsignedIntegerAttribute(buf, "id", id);
|
||||
buf.append("/>\n");
|
||||
buf.append(" <addr");
|
||||
Varnode.appendSpaceOffset(buf, addr);
|
||||
buf.append("/>\n");
|
||||
buf.append(" <rangelist/>\n");
|
||||
buf.append("/>\n ");
|
||||
AddressXML.buildXML(buf, addr);
|
||||
buf.append("\n <rangelist/>\n");
|
||||
buf.append("</mapsym>\n");
|
||||
getMapped(namespace, buf.toString());
|
||||
}
|
||||
|
@ -711,7 +738,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]);
|
||||
|
@ -733,7 +760,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) {
|
||||
|
@ -751,25 +778,44 @@ public class DecompileDebug {
|
|||
else {
|
||||
buf.append("none");
|
||||
}
|
||||
buf.append("\"><addr");
|
||||
Varnode.appendSpaceOffset(buf,func.getEntryPoint());
|
||||
buf.append("/><addr");
|
||||
Varnode.appendSpaceOffset(buf, addr);
|
||||
buf.append("/></flow>\n");
|
||||
buf.append("\">");
|
||||
AddressXML.buildXML(buf, func.getEntryPoint());
|
||||
AddressXML.buildXML(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 <addr");
|
||||
Varnode.appendSpaceOffset(buf, addr);
|
||||
buf.append("/>\n <payload><![CDATA[\n");
|
||||
buf.append(">\n ");
|
||||
AddressXML.buildXML(buf, addr);
|
||||
buf.append("\n <payload><![CDATA[\n");
|
||||
buf.append(payload);
|
||||
buf.append("\n]]></payload>\n</inject>\n");
|
||||
inject.add(buf.toString());
|
||||
|
||||
PcodeInjectLibrary library = program.getCompilerSpec().getPcodeInjectLibrary();
|
||||
if (library.hasProgramPayload(name, injectType)) {
|
||||
InjectPayload programPayload = library.getPayload(injectType, name);
|
||||
String title =
|
||||
(injectType == InjectPayload.CALLFIXUP_TYPE) ? "callfixup_" : "callotherfixup_";
|
||||
title = title + name;
|
||||
specExtensions.put(title, programPayload);
|
||||
}
|
||||
}
|
||||
|
||||
public void addPossiblePrototypeExtension(Function testFunc) {
|
||||
PrototypeModel model = testFunc.getCallingConvention();
|
||||
if (model == null) {
|
||||
return;
|
||||
}
|
||||
if (model.isProgramExtension()) {
|
||||
String title = "prototype_" + model.getName();
|
||||
specExtensions.put(title, model);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,7 +27,9 @@ 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;
|
||||
|
@ -404,7 +406,7 @@ public class DecompileOptions {
|
|||
codeViewerBackgroundColor = CODE_VIEWER_BACKGROUND_COLOR;
|
||||
defaultFont = DEFAULT_FONT;
|
||||
displayLineNumbers = LINE_NUMBER_DEF;
|
||||
displayLanguage = BasicCompilerSpec.DECOMPILER_OUTPUT_DEF;
|
||||
displayLanguage = ProgramCompilerSpec.DECOMPILER_OUTPUT_DEF;
|
||||
protoEvalModel = "default";
|
||||
decompileTimeoutSeconds = SUGGESTED_DECOMPILE_TIMEOUT_SECS;
|
||||
payloadLimitMBytes = SUGGESTED_MAX_PAYLOAD_BYTES;
|
||||
|
@ -503,21 +505,21 @@ public class DecompileOptions {
|
|||
*/
|
||||
public void grabFromProgram(Program program) {
|
||||
// Default values, even if there is no program
|
||||
displayLanguage = BasicCompilerSpec.DECOMPILER_OUTPUT_DEF;
|
||||
displayLanguage = ProgramCompilerSpec.DECOMPILER_OUTPUT_DEF;
|
||||
protoEvalModel = "default";
|
||||
if (program == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
CompilerSpec cspec = program.getCompilerSpec();
|
||||
PrototypeModel model = (PrototypeModel) cspec.getPrototypeEvaluationModel(program);
|
||||
PrototypeModel model = cspec.getPrototypeEvaluationModel(EvaluationModelType.EVAL_CURRENT);
|
||||
if (model != null) {
|
||||
String modelname = model.getName();
|
||||
if (modelname != null) {
|
||||
protoEvalModel = modelname;
|
||||
}
|
||||
}
|
||||
displayLanguage = cspec.getDecompilerOutputLanguage(program);
|
||||
displayLanguage = cspec.getDecompilerOutputLanguage();
|
||||
}
|
||||
|
||||
public String getProtoEvalModel() {
|
||||
|
|
|
@ -4,19 +4,15 @@
|
|||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*
|
||||
* Created on Jun 3, 2005
|
||||
*
|
||||
*/
|
||||
package ghidra.app.decompiler;
|
||||
|
||||
import java.io.*;
|
||||
|
|
|
@ -29,6 +29,7 @@ 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;
|
||||
|
@ -231,6 +232,9 @@ public class DecompilePlugin extends Plugin {
|
|||
if (event instanceof ProgramActivatedPluginEvent) {
|
||||
currentProgram = ((ProgramActivatedPluginEvent) event).getActiveProgram();
|
||||
connectedProvider.doSetProgram(currentProgram);
|
||||
if (currentProgram != null) {
|
||||
SpecExtension.registerOptions(currentProgram);
|
||||
}
|
||||
}
|
||||
else if (event instanceof ProgramLocationPluginEvent) {
|
||||
ProgramLocation location = ((ProgramLocationPluginEvent) event).getLocation();
|
||||
|
|
|
@ -36,11 +36,11 @@ import ghidra.app.plugin.core.decompile.actions.*;
|
|||
import ghidra.app.services.*;
|
||||
import ghidra.app.util.HelpTopics;
|
||||
import ghidra.app.util.HighlightProvider;
|
||||
import ghidra.framework.model.DomainObjectChangedEvent;
|
||||
import ghidra.framework.model.DomainObjectListener;
|
||||
import ghidra.framework.model.*;
|
||||
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,17 +307,33 @@ public class DecompilerProvider extends NavigatableComponentProviderAdapter
|
|||
|
||||
@Override
|
||||
public void domainObjectChanged(DomainObjectChangedEvent ev) {
|
||||
if (!isVisible()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 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(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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
redecompileUpdater.update();
|
||||
|
||||
// Trigger a redecompile an any program change if the window is active
|
||||
if (isVisible()) {
|
||||
redecompileUpdater.update();
|
||||
}
|
||||
}
|
||||
|
||||
private void doRefresh() {
|
||||
|
|
|
@ -26,6 +26,7 @@ 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;
|
||||
|
@ -46,7 +47,7 @@ public class DecompilerValidator extends PostAnalysisValidator {
|
|||
List<Function> functions = filterFunctions(program, iter, monitor);
|
||||
|
||||
DecompilerCallback<String> callback =
|
||||
new DecompilerCallback<String>(program, new DecompilerValidatorConfigurer()) {
|
||||
new DecompilerCallback<>(program, new DecompilerValidatorConfigurer()) {
|
||||
|
||||
@Override
|
||||
public String process(DecompileResults results, TaskMonitor m) throws Exception {
|
||||
|
@ -147,7 +148,8 @@ public class DecompilerValidator extends PostAnalysisValidator {
|
|||
private DecompileOptions getDecompilerOptions() {
|
||||
try {
|
||||
CompilerSpec spec = program.getCompilerSpec();
|
||||
PrototypeModel model = (PrototypeModel) spec.getPrototypeEvaluationModel(program);
|
||||
PrototypeModel model =
|
||||
spec.getPrototypeEvaluationModel(EvaluationModelType.EVAL_CURRENT);
|
||||
options.setProtoEvalModel(model.getName());
|
||||
}
|
||||
catch (Exception e) {
|
||||
|
|
|
@ -29,6 +29,7 @@ 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 {
|
||||
|
@ -171,4 +172,34 @@ public abstract class AbstractDecompilerTest extends AbstractProgramBasedTest {
|
|||
assertEquals(tokenText, text);
|
||||
}
|
||||
}
|
||||
|
||||
protected ClangTextField getLineStarting(String val) {
|
||||
DecompilerPanel panel = provider.getDecompilerPanel();
|
||||
List<Field> fields = panel.getFields();
|
||||
for (Field field : fields) {
|
||||
ClangTextField textField = (ClangTextField) field;
|
||||
String text = textField.getText().trim();
|
||||
if (text.startsWith(val)) {
|
||||
return textField;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected ClangTextField getLineContaining(String val) {
|
||||
DecompilerPanel panel = provider.getDecompilerPanel();
|
||||
List<Field> fields = panel.getFields();
|
||||
for (Field field : fields) {
|
||||
ClangTextField textField = (ClangTextField) field;
|
||||
String text = textField.getText();
|
||||
if (text.contains(val)) {
|
||||
return textField;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected HighFunction getHighFunction() {
|
||||
return provider.getController().getHighFunction();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,11 +17,8 @@ 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;
|
||||
|
@ -30,7 +27,6 @@ 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;
|
||||
|
@ -49,36 +45,6 @@ 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();
|
||||
|
@ -114,6 +80,7 @@ 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(),
|
||||
|
|
|
@ -0,0 +1,259 @@
|
|||
/* ###
|
||||
* 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);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue