mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-06 03:50:02 +02:00
Merge branch 'master' of gitlab.evoforge.org:ghidra/ghidra into debugger
This commit is contained in:
commit
102f4e8a7a
34 changed files with 701 additions and 328 deletions
|
@ -17,6 +17,7 @@
|
||||||
<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/>
|
<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/>
|
||||||
<listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
|
<listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
|
||||||
</listAttribute>
|
</listAttribute>
|
||||||
|
<booleanAttribute key="org.eclipse.jdt.launching.ATTR_ATTR_USE_ARGFILE" value="false"/>
|
||||||
<booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_CLASSPATH_ONLY_JAR" value="false"/>
|
<booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_CLASSPATH_ONLY_JAR" value="false"/>
|
||||||
<booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="true"/>
|
<booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="true"/>
|
||||||
<listAttribute key="org.eclipse.jdt.launching.CLASSPATH">
|
<listAttribute key="org.eclipse.jdt.launching.CLASSPATH">
|
||||||
|
@ -29,5 +30,5 @@
|
||||||
<stringAttribute key="org.eclipse.jdt.launching.MODULE_NAME" value="Framework Utility"/>
|
<stringAttribute key="org.eclipse.jdt.launching.MODULE_NAME" value="Framework Utility"/>
|
||||||
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="ghidra.GhidraRun"/>
|
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="ghidra.GhidraRun"/>
|
||||||
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="Framework Utility"/>
|
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="Framework Utility"/>
|
||||||
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-XX:+IgnoreUnrecognizedVMOptions -Djava.system.class.loader=ghidra.GhidraClassLoader -Xshare:off -Dfile.encoding=UTF8 -Duser.country=US -Duser.language=en -Dsun.java2d.pmoffscreen=false -Dsun.java2d.xrender=true -Dsun.java2d.d3d=false -Xdock:name="Ghidra" -Dvisualvm.display.name=Ghidra -Dpython.console.encoding=UTF-8 -DContinuesInterceptor.disabled=true"/>
|
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-XX:+IgnoreUnrecognizedVMOptions -Djava.system.class.loader=ghidra.GhidraClassLoader -Xshare:off -Dfile.encoding=UTF8 -Duser.country=US -Duser.language=en -Dsun.java2d.pmoffscreen=false -Dsun.java2d.xrender=true -Dsun.java2d.d3d=false -Xdock:name="Ghidra" -Dvisualvm.display.name=Ghidra -Dpython.console.encoding=UTF-8 -DContinuesInterceptor.disabled=true --illegal-access=permit"/>
|
||||||
</launchConfiguration>
|
</launchConfiguration>
|
||||||
|
|
|
@ -36,7 +36,7 @@ public class PropagateConstantReferences extends GhidraScript {
|
||||||
public void run() throws Exception {
|
public void run() throws Exception {
|
||||||
long numInstructions = currentProgram.getListing().getNumInstructions();
|
long numInstructions = currentProgram.getListing().getNumInstructions();
|
||||||
monitor.initialize((int) (numInstructions));
|
monitor.initialize((int) (numInstructions));
|
||||||
monitor.setMessage("Constant Propogation Markup");
|
monitor.setMessage("Constant Propagation Markup");
|
||||||
|
|
||||||
// set up the address set to restrict processing
|
// set up the address set to restrict processing
|
||||||
AddressSet restrictedSet =
|
AddressSet restrictedSet =
|
||||||
|
|
|
@ -57,7 +57,7 @@ public class PropagateX86ConstantReferences extends GhidraScript {
|
||||||
public void run() throws Exception {
|
public void run() throws Exception {
|
||||||
long numInstructions = currentProgram.getListing().getNumInstructions();
|
long numInstructions = currentProgram.getListing().getNumInstructions();
|
||||||
monitor.initialize((int) (numInstructions));
|
monitor.initialize((int) (numInstructions));
|
||||||
monitor.setMessage("Constant Propogation Markup");
|
monitor.setMessage("Constant Propagation Markup");
|
||||||
|
|
||||||
// set up the address set to restrict processing
|
// set up the address set to restrict processing
|
||||||
AddressSet restrictedSet = new AddressSet(currentSelection);
|
AddressSet restrictedSet = new AddressSet(currentSelection);
|
||||||
|
|
|
@ -37,7 +37,6 @@ import ghidra.app.plugin.assembler.Assembler;
|
||||||
import ghidra.app.plugin.assembler.Assemblers;
|
import ghidra.app.plugin.assembler.Assemblers;
|
||||||
import ghidra.app.plugin.core.assembler.AssemblyDualTextField.*;
|
import ghidra.app.plugin.core.assembler.AssemblyDualTextField.*;
|
||||||
import ghidra.app.plugin.core.codebrowser.CodeViewerProvider;
|
import ghidra.app.plugin.core.codebrowser.CodeViewerProvider;
|
||||||
import ghidra.app.util.PluginConstants;
|
|
||||||
import ghidra.app.util.viewer.field.ListingField;
|
import ghidra.app.util.viewer.field.ListingField;
|
||||||
import ghidra.app.util.viewer.listingpanel.ListingModelAdapter;
|
import ghidra.app.util.viewer.listingpanel.ListingModelAdapter;
|
||||||
import ghidra.app.util.viewer.listingpanel.ListingPanel;
|
import ghidra.app.util.viewer.listingpanel.ListingPanel;
|
||||||
|
@ -78,7 +77,7 @@ public class AssembleDockingAction extends DockingAction {
|
||||||
private Language lang;
|
private Language lang;
|
||||||
private Assembler assembler;
|
private Assembler assembler;
|
||||||
private final MyListener listener = new MyListener();
|
private final MyListener listener = new MyListener();
|
||||||
private PluginTool tool;
|
//private PluginTool tool;
|
||||||
|
|
||||||
// Callback to keep the autocompleter positioned under the fields
|
// Callback to keep the autocompleter positioned under the fields
|
||||||
private FieldPanelOverLayoutListener autoCompleteMover = (FieldPanelOverLayoutEvent ev) -> {
|
private FieldPanelOverLayoutListener autoCompleteMover = (FieldPanelOverLayoutEvent ev) -> {
|
||||||
|
@ -159,23 +158,7 @@ public class AssembleDockingAction extends DockingAction {
|
||||||
*/
|
*/
|
||||||
public AssembleDockingAction(PluginTool tool, String name, String owner) {
|
public AssembleDockingAction(PluginTool tool, String name, String owner) {
|
||||||
this(name, owner);
|
this(name, owner);
|
||||||
this.tool = tool;
|
//this.tool = tool;
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void dispose() {
|
|
||||||
super.dispose();
|
|
||||||
input.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void onFirstInvocation() {
|
|
||||||
ComponentProvider prov = tool.getComponentProvider(PluginConstants.CODE_BROWSER);
|
|
||||||
cv = (CodeViewerProvider) prov;
|
|
||||||
listpane = cv.getListingPanel();
|
|
||||||
codepane = listpane.getFieldPanel();
|
|
||||||
|
|
||||||
fieldLayoutManager = new FieldPanelOverLayoutManager(codepane);
|
|
||||||
codepane.setLayout(fieldLayoutManager);
|
|
||||||
|
|
||||||
// If I lose focus, cancel the assembly
|
// If I lose focus, cancel the assembly
|
||||||
input.addFocusListener(new FocusListener() {
|
input.addFocusListener(new FocusListener() {
|
||||||
|
@ -189,15 +172,38 @@ public class AssembleDockingAction extends DockingAction {
|
||||||
cancel();
|
cancel();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
input.getMnemonicField().setBorder(BorderFactory.createLineBorder(Color.RED, 2));
|
input.getMnemonicField().setBorder(BorderFactory.createLineBorder(Color.RED, 2));
|
||||||
input.getOperandsField().setBorder(BorderFactory.createLineBorder(Color.RED, 2));
|
input.getOperandsField().setBorder(BorderFactory.createLineBorder(Color.RED, 2));
|
||||||
input.getAssemblyField().setBorder(BorderFactory.createLineBorder(Color.RED, 2));
|
input.getAssemblyField().setBorder(BorderFactory.createLineBorder(Color.RED, 2));
|
||||||
|
|
||||||
input.getAutocompleter().addAutocompletionListener(listener);
|
input.getAutocompleter().addAutocompletionListener(listener);
|
||||||
input.addKeyListener(listener);
|
input.addKeyListener(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void dispose() {
|
||||||
|
super.dispose();
|
||||||
|
input.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void prepareLayout(ActionContext context) {
|
||||||
|
ComponentProvider prov = context.getComponentProvider();
|
||||||
|
if (cv != prov) {
|
||||||
|
if (cv != null) {
|
||||||
|
codepane.setLayout(null);
|
||||||
|
fieldLayoutManager.removeLayoutListener(autoCompleteMover);
|
||||||
|
}
|
||||||
|
|
||||||
|
cv = (CodeViewerProvider) prov;
|
||||||
|
listpane = cv.getListingPanel();
|
||||||
|
codepane = listpane.getFieldPanel();
|
||||||
|
|
||||||
|
fieldLayoutManager = new FieldPanelOverLayoutManager(codepane);
|
||||||
|
codepane.setLayout(fieldLayoutManager);
|
||||||
fieldLayoutManager.addLayoutListener(autoCompleteMover);
|
fieldLayoutManager.addLayoutListener(autoCompleteMover);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cancel the current assembly action
|
* Cancel the current assembly action
|
||||||
|
@ -265,11 +271,13 @@ public class AssembleDockingAction extends DockingAction {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(ActionContext context) {
|
public void actionPerformed(ActionContext context) {
|
||||||
if (cv == null) {
|
if (!(context instanceof ListingActionContext)) {
|
||||||
onFirstInvocation();
|
return;
|
||||||
}
|
}
|
||||||
|
prepareLayout(context);
|
||||||
|
ListingActionContext lac = (ListingActionContext) context;
|
||||||
|
|
||||||
ProgramLocation cur = cv.getLocation();
|
ProgramLocation cur = lac.getLocation();
|
||||||
|
|
||||||
prog = cur.getProgram();
|
prog = cur.getProgram();
|
||||||
addr = cur.getAddress();
|
addr = cur.getAddress();
|
||||||
|
@ -356,6 +364,7 @@ public class AssembleDockingAction extends DockingAction {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isAddToPopup(ActionContext context) {
|
public boolean isAddToPopup(ActionContext context) {
|
||||||
|
|
||||||
// currently only works on a listing
|
// currently only works on a listing
|
||||||
if (!(context instanceof ListingActionContext)) {
|
if (!(context instanceof ListingActionContext)) {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -111,7 +111,6 @@ public class ElfSymbol implements ByteArrayConverter {
|
||||||
* @param reader to read symbol from
|
* @param reader to read symbol from
|
||||||
* @param symbolIndex index of the symbol to read
|
* @param symbolIndex index of the symbol to read
|
||||||
* @param symbolTable symbol table to associate the symbol to
|
* @param symbolTable symbol table to associate the symbol to
|
||||||
* @param stringTable string table to read symbols from
|
|
||||||
* @param header else header
|
* @param header else header
|
||||||
* @return newly created ElfSymbol
|
* @return newly created ElfSymbol
|
||||||
*
|
*
|
||||||
|
|
|
@ -17,6 +17,7 @@ src/decompile/datatests/forloop_thruspecial.xml||GHIDRA||||END|
|
||||||
src/decompile/datatests/forloop_varused.xml||GHIDRA||||END|
|
src/decompile/datatests/forloop_varused.xml||GHIDRA||||END|
|
||||||
src/decompile/datatests/forloop_withskip.xml||GHIDRA||||END|
|
src/decompile/datatests/forloop_withskip.xml||GHIDRA||||END|
|
||||||
src/decompile/datatests/loopcomment.xml||GHIDRA||||END|
|
src/decompile/datatests/loopcomment.xml||GHIDRA||||END|
|
||||||
|
src/decompile/datatests/multiret.xml||GHIDRA||||END|
|
||||||
src/decompile/datatests/namespace.xml||GHIDRA||||END|
|
src/decompile/datatests/namespace.xml||GHIDRA||||END|
|
||||||
src/decompile/datatests/nestedoffset.xml||GHIDRA||||END|
|
src/decompile/datatests/nestedoffset.xml||GHIDRA||||END|
|
||||||
src/decompile/datatests/noforloop_alias.xml||GHIDRA||||END|
|
src/decompile/datatests/noforloop_alias.xml||GHIDRA||||END|
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
vector<ArchitectureCapability *> ArchitectureCapability::thelist;
|
vector<ArchitectureCapability *> ArchitectureCapability::thelist;
|
||||||
|
|
||||||
const uint4 ArchitectureCapability::majorversion = 4;
|
const uint4 ArchitectureCapability::majorversion = 4;
|
||||||
const uint4 ArchitectureCapability::minorversion = 0;
|
const uint4 ArchitectureCapability::minorversion = 1;
|
||||||
|
|
||||||
/// This builds a list of just the ArchitectureCapability extensions
|
/// This builds a list of just the ArchitectureCapability extensions
|
||||||
void ArchitectureCapability::initialize(void)
|
void ArchitectureCapability::initialize(void)
|
||||||
|
|
|
@ -1852,7 +1852,7 @@ int4 ActionReturnRecovery::apply(Funcdata &data)
|
||||||
int4 slot = trial.getSlot();
|
int4 slot = trial.getSlot();
|
||||||
vn = op->getIn(slot);
|
vn = op->getIn(slot);
|
||||||
if (ancestorReal.execute(op,slot,&trial,false))
|
if (ancestorReal.execute(op,slot,&trial,false))
|
||||||
if (data.ancestorOpUse(maxancestor,vn,op,trial))
|
if (data.ancestorOpUse(maxancestor,vn,op,trial,0))
|
||||||
trial.markActive(); // This varnode sees active use as a parameter
|
trial.markActive(); // This varnode sees active use as a parameter
|
||||||
count += 1;
|
count += 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
implement these models provides the quickest inroad into
|
implement these models provides the quickest inroad into
|
||||||
obtaining an overall understanding of the code.
|
obtaining an overall understanding of the code.
|
||||||
|
|
||||||
We list all these fundemental classes here, loosely grouped
|
We list all these fundamental classes here, loosely grouped
|
||||||
as follows. There is one set of classes that describe the
|
as follows. There is one set of classes that describe the
|
||||||
\e Syntax \e Trees, which are built up from the original p-code,
|
\e Syntax \e Trees, which are built up from the original p-code,
|
||||||
and transformed during the decompiler's simplification process.
|
and transformed during the decompiler's simplification process.
|
||||||
|
@ -44,7 +44,7 @@
|
||||||
- A place within the reverse engineering model where data
|
- A place within the reverse engineering model where data
|
||||||
can be stored. The typical address spaces are \b ram,
|
can be stored. The typical address spaces are \b ram,
|
||||||
modeling the main databus of a processor, and \b register,
|
modeling the main databus of a processor, and \b register,
|
||||||
modeling a processors on board registers. Data is stored a
|
modeling a processor's on board registers. Data is stored a
|
||||||
byte at a time at \b offsets within the AddrSpace.
|
byte at a time at \b offsets within the AddrSpace.
|
||||||
.
|
.
|
||||||
- Address
|
- Address
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/* ###
|
/* ###
|
||||||
* IP: GHIDRA
|
* IP: GHIDRA
|
||||||
* REVIEWED: YES
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -38,7 +37,7 @@
|
||||||
the main code workflow.
|
the main code workflow.
|
||||||
|
|
||||||
The library provides its own Register
|
The library provides its own Register
|
||||||
Transfer Languate (RTL), referred to internally as \b p-code,
|
Transfer Language (RTL), referred to internally as \b p-code,
|
||||||
which is designed specifically for reverse engineering
|
which is designed specifically for reverse engineering
|
||||||
applications. The disassembly of processor specific machine-code
|
applications. The disassembly of processor specific machine-code
|
||||||
languages, and subsequent translation into \b p-code, forms
|
languages, and subsequent translation into \b p-code, forms
|
||||||
|
@ -275,7 +274,7 @@
|
||||||
about the variables it analyzes, as this kind of
|
about the variables it analyzes, as this kind of
|
||||||
information is generally not present in the input
|
information is generally not present in the input
|
||||||
binary. Some information can be gathered about a
|
binary. Some information can be gathered about a
|
||||||
variable, based on the instructions it is used in (.i.e
|
variable, based on the instructions it is used in (i.e.
|
||||||
if it is used in a floating point instruction). Other
|
if it is used in a floating point instruction). Other
|
||||||
information about type might be available from header
|
information about type might be available from header
|
||||||
files or from the user. Once this is gathered, the
|
files or from the user. Once this is gathered, the
|
||||||
|
@ -301,7 +300,7 @@
|
||||||
compiler would, but to simplify and normalize for
|
compiler would, but to simplify and normalize for
|
||||||
easier understanding and recognition by human analysts
|
easier understanding and recognition by human analysts
|
||||||
(and follow on machine processing). Typical examples
|
(and follow on machine processing). Typical examples
|
||||||
of transforms include, copy propagation, constant
|
of transforms include: copy propagation, constant
|
||||||
propagation, collecting terms, cancellation of
|
propagation, collecting terms, cancellation of
|
||||||
operators and other algebraic simplifications, undoing
|
operators and other algebraic simplifications, undoing
|
||||||
multiplication and division optimizations, commuting
|
multiplication and division optimizations, commuting
|
||||||
|
@ -373,7 +372,7 @@
|
||||||
|
|
||||||
Even after the initial merging of variables in phase 1,
|
Even after the initial merging of variables in phase 1,
|
||||||
there are generally still too many for normal C code. So
|
there are generally still too many for normal C code. So
|
||||||
the decompiler, does additional, more speculative merging.
|
the decompiler does additional, more speculative merging.
|
||||||
It first tries to merge the inputs and outputs of copy
|
It first tries to merge the inputs and outputs of copy
|
||||||
operations, and then the inputs and outputs of more
|
operations, and then the inputs and outputs of more
|
||||||
general operations. And finally, merging is attempted on
|
general operations. And finally, merging is attempted on
|
||||||
|
|
|
@ -3174,17 +3174,20 @@ void FuncProto::setOutputLock(bool val)
|
||||||
store->getOutput()->setTypeLock(val);
|
store->getOutput()->setTypeLock(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This value can be used as a hint as to how much of the return value is important and
|
/// Provide a hint as to how many bytes of the return value are important.
|
||||||
/// is used to inform the dead code \e consume algorithm.
|
/// The smallest hint is used to inform the dead-code removal algorithm.
|
||||||
/// \param val is the estimated number of bytes or 0
|
/// \param val is the hint (number of bytes or 0 for all bytes)
|
||||||
/// \return \b true if the value was changed
|
/// \return \b true if the smallest hint has changed
|
||||||
bool FuncProto::setReturnBytesConsumed(int4 val)
|
bool FuncProto::setReturnBytesConsumed(int4 val)
|
||||||
|
|
||||||
{
|
{
|
||||||
int4 oldVal = returnBytesConsumed;
|
if (val == 0)
|
||||||
if (oldVal == 0 || val < oldVal)
|
return false;
|
||||||
|
if (returnBytesConsumed == 0 || val < returnBytesConsumed) {
|
||||||
returnBytesConsumed = val;
|
returnBytesConsumed = val;
|
||||||
return (oldVal != val);
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Assuming \b this prototype is locked, calculate the \e extrapop
|
/// \brief Assuming \b this prototype is locked, calculate the \e extrapop
|
||||||
|
@ -4744,7 +4747,7 @@ void FuncCallSpecs::checkInputTrialUse(Funcdata &data,AliasChecker &aliascheck)
|
||||||
trial.markNoUse();
|
trial.markNoUse();
|
||||||
}
|
}
|
||||||
else if (ancestorReal.execute(op,slot,&trial,false)) {
|
else if (ancestorReal.execute(op,slot,&trial,false)) {
|
||||||
if (data.ancestorOpUse(maxancestor,vn,op,trial))
|
if (data.ancestorOpUse(maxancestor,vn,op,trial,0))
|
||||||
trial.markActive();
|
trial.markActive();
|
||||||
else
|
else
|
||||||
trial.markInactive();
|
trial.markInactive();
|
||||||
|
@ -4754,7 +4757,7 @@ void FuncCallSpecs::checkInputTrialUse(Funcdata &data,AliasChecker &aliascheck)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (ancestorReal.execute(op,slot,&trial,true)) {
|
if (ancestorReal.execute(op,slot,&trial,true)) {
|
||||||
if (data.ancestorOpUse(maxancestor,vn,op,trial)) {
|
if (data.ancestorOpUse(maxancestor,vn,op,trial,0)) {
|
||||||
trial.markActive();
|
trial.markActive();
|
||||||
if (trial.hasCondExeEffect())
|
if (trial.hasCondExeEffect())
|
||||||
activeinput.markNeedsFinalCheck();
|
activeinput.markNeedsFinalCheck();
|
||||||
|
|
|
@ -58,6 +58,11 @@ class Funcdata {
|
||||||
baddata_present = 0x800, ///< Set if function flowed into bad data
|
baddata_present = 0x800, ///< Set if function flowed into bad data
|
||||||
double_precis_on = 0x1000 ///< Set if we are performing double precision recovery
|
double_precis_on = 0x1000 ///< Set if we are performing double precision recovery
|
||||||
};
|
};
|
||||||
|
enum {
|
||||||
|
traverse_actionalt = 1, ///< Alternate path traverses a solid action or \e non-incidental COPY
|
||||||
|
traverse_indirect = 2, ///< Main path traverses an INDIRECT
|
||||||
|
traverse_indirectalt = 4 ///< Alternate path traverses an INDIRECT
|
||||||
|
};
|
||||||
uint4 flags; ///< Boolean properties associated with \b this function
|
uint4 flags; ///< Boolean properties associated with \b this function
|
||||||
uint4 clean_up_index; ///< Creation index of first Varnode created after start of cleanup
|
uint4 clean_up_index; ///< Creation index of first Varnode created after start of cleanup
|
||||||
uint4 high_level_index; ///< Creation index of first Varnode created after HighVariables are created
|
uint4 high_level_index; ///< Creation index of first Varnode created after HighVariables are created
|
||||||
|
@ -116,6 +121,7 @@ class Funcdata {
|
||||||
void nodeSplitCloneVarnode(PcodeOp *op,PcodeOp *newop);
|
void nodeSplitCloneVarnode(PcodeOp *op,PcodeOp *newop);
|
||||||
void nodeSplitRawDuplicate(BlockBasic *b,BlockBasic *bprime);
|
void nodeSplitRawDuplicate(BlockBasic *b,BlockBasic *bprime);
|
||||||
void nodeSplitInputPatch(BlockBasic *b,BlockBasic *bprime,int4 inedge);
|
void nodeSplitInputPatch(BlockBasic *b,BlockBasic *bprime,int4 inedge);
|
||||||
|
static bool isAlternatePathValid(const Varnode *vn,uint4 flags);
|
||||||
static bool descendantsOutside(Varnode *vn);
|
static bool descendantsOutside(Varnode *vn);
|
||||||
static void saveVarnodeXml(ostream &s,VarnodeLocSet::const_iterator iter,VarnodeLocSet::const_iterator enditer);
|
static void saveVarnodeXml(ostream &s,VarnodeLocSet::const_iterator iter,VarnodeLocSet::const_iterator enditer);
|
||||||
static bool checkIndirectUse(Varnode *vn);
|
static bool checkIndirectUse(Varnode *vn);
|
||||||
|
@ -363,9 +369,9 @@ public:
|
||||||
|
|
||||||
HighVariable *findHigh(const string &name) const; ///< Find a high-level variable by name
|
HighVariable *findHigh(const string &name) const; ///< Find a high-level variable by name
|
||||||
void mapGlobals(void); ///< Make sure there is a Symbol entry for all global Varnodes
|
void mapGlobals(void); ///< Make sure there is a Symbol entry for all global Varnodes
|
||||||
bool checkCallDoubleUse(const PcodeOp *opmatch,const PcodeOp *op,const Varnode *vn,const ParamTrial &trial) const;
|
bool checkCallDoubleUse(const PcodeOp *opmatch,const PcodeOp *op,const Varnode *vn,uint4 flags,const ParamTrial &trial) const;
|
||||||
bool onlyOpUse(const Varnode *invn,const PcodeOp *opmatch,const ParamTrial &trial) const;
|
bool onlyOpUse(const Varnode *invn,const PcodeOp *opmatch,const ParamTrial &trial,uint4 mainFlags) const;
|
||||||
bool ancestorOpUse(int4 maxlevel,const Varnode *invn,const PcodeOp *op,ParamTrial &trial) const;
|
bool ancestorOpUse(int4 maxlevel,const Varnode *invn,const PcodeOp *op,ParamTrial &trial,uint4 mainFlags) const;
|
||||||
bool syncVarnodesWithSymbols(const ScopeLocal *lm,bool typesyes);
|
bool syncVarnodesWithSymbols(const ScopeLocal *lm,bool typesyes);
|
||||||
void transferVarnodeProperties(Varnode *vn,Varnode *newVn,int4 lsbOffset);
|
void transferVarnodeProperties(Varnode *vn,Varnode *newVn,int4 lsbOffset);
|
||||||
bool fillinReadOnly(Varnode *vn); ///< Replace the given Varnode with its (constant) value in the load image
|
bool fillinReadOnly(Varnode *vn); ///< Replace the given Varnode with its (constant) value in the load image
|
||||||
|
|
|
@ -1472,6 +1472,30 @@ void Funcdata::mapGlobals(void)
|
||||||
warningHeader("Globals starting with '_' overlap smaller symbols at the same address");
|
warningHeader("Globals starting with '_' overlap smaller symbols at the same address");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief Return \b true if the alternate path looks more valid than the main path.
|
||||||
|
///
|
||||||
|
/// Two different paths from a common Varnode each terminate at a CALL, CALLIND, or RETURN.
|
||||||
|
/// Evaluate which path most likely represents actual parameter/return value passing,
|
||||||
|
/// based on traversal information about each path.
|
||||||
|
/// \param vn is the Varnode terminating the \e alternate path
|
||||||
|
/// \param flags indicates traversals for both paths
|
||||||
|
/// \return \b true if the alternate path is preferred
|
||||||
|
bool Funcdata::isAlternatePathValid(const Varnode *vn,uint4 flags)
|
||||||
|
|
||||||
|
{
|
||||||
|
if ((flags & (traverse_indirect | traverse_indirectalt)) == traverse_indirect)
|
||||||
|
// If main path traversed an INDIRECT but the alternate did not
|
||||||
|
return true; // Main path traversed INDIRECT, alternate did not
|
||||||
|
if ((flags & (traverse_indirect | traverse_indirectalt)) == traverse_indirectalt)
|
||||||
|
return false; // Alternate path traversed INDIRECT, main did not
|
||||||
|
if ((flags & traverse_actionalt) != 0)
|
||||||
|
return true; // Alternate path traversed a dedicated COPY
|
||||||
|
if (vn->loneDescend() == (PcodeOp*)0) return false;
|
||||||
|
const PcodeOp *op = vn->getDef();
|
||||||
|
if (op == (PcodeOp*)0) return true;
|
||||||
|
return !op->isMarker(); // MULTIEQUAL or INDIRECT indicates multiple values
|
||||||
|
}
|
||||||
|
|
||||||
/// \brief Test for legitimate double use of a parameter trial
|
/// \brief Test for legitimate double use of a parameter trial
|
||||||
///
|
///
|
||||||
/// The given trial is a \e putative input to first CALL, but can also trace its data-flow
|
/// The given trial is a \e putative input to first CALL, but can also trace its data-flow
|
||||||
|
@ -1480,9 +1504,10 @@ void Funcdata::mapGlobals(void)
|
||||||
/// \param opmatch is the first CALL linked to the trial
|
/// \param opmatch is the first CALL linked to the trial
|
||||||
/// \param op is the second CALL
|
/// \param op is the second CALL
|
||||||
/// \param vn is the Varnode parameter for the second CALL
|
/// \param vn is the Varnode parameter for the second CALL
|
||||||
|
/// \param flags indicates what p-code ops were crossed to reach \e vn
|
||||||
/// \param trial is the given parameter trial
|
/// \param trial is the given parameter trial
|
||||||
/// \return \b true for a legitimate double use
|
/// \return \b true for a legitimate double use
|
||||||
bool Funcdata::checkCallDoubleUse(const PcodeOp *opmatch,const PcodeOp *op,const Varnode *vn,const ParamTrial &trial) const
|
bool Funcdata::checkCallDoubleUse(const PcodeOp *opmatch,const PcodeOp *op,const Varnode *vn,uint4 flags,const ParamTrial &trial) const
|
||||||
|
|
||||||
{
|
{
|
||||||
int4 j = op->getSlot(vn);
|
int4 j = op->getSlot(vn);
|
||||||
|
@ -1511,7 +1536,13 @@ bool Funcdata::checkCallDoubleUse(const PcodeOp *opmatch,const PcodeOp *op,const
|
||||||
|
|
||||||
if (fc->isInputActive()) {
|
if (fc->isInputActive()) {
|
||||||
const ParamTrial &curtrial( fc->getActiveInput()->getTrialForInputVarnode(j) );
|
const ParamTrial &curtrial( fc->getActiveInput()->getTrialForInputVarnode(j) );
|
||||||
if ((!curtrial.isChecked())||(!curtrial.isActive())) return true;
|
if (curtrial.isChecked()) {
|
||||||
|
if (curtrial.isActive())
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (isAlternatePathValid(vn,flags))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1523,28 +1554,31 @@ bool Funcdata::checkCallDoubleUse(const PcodeOp *opmatch,const PcodeOp *op,const
|
||||||
/// \param invn is the given Varnode
|
/// \param invn is the given Varnode
|
||||||
/// \param opmatch is the putative CALL op using the Varnode for parameter passing
|
/// \param opmatch is the putative CALL op using the Varnode for parameter passing
|
||||||
/// \param trial is the parameter trial object associated with the Varnode
|
/// \param trial is the parameter trial object associated with the Varnode
|
||||||
|
/// \param mainFlags are flags describing traversals along the \e main path, from \e invn to \e opmatch
|
||||||
/// \return \b true if the Varnode seems only to be used as parameter to \b opmatch
|
/// \return \b true if the Varnode seems only to be used as parameter to \b opmatch
|
||||||
bool Funcdata::onlyOpUse(const Varnode *invn,const PcodeOp *opmatch,const ParamTrial &trial) const
|
bool Funcdata::onlyOpUse(const Varnode *invn,const PcodeOp *opmatch,const ParamTrial &trial,uint4 mainFlags) const
|
||||||
|
|
||||||
{
|
{
|
||||||
vector<const Varnode *> varlist;
|
vector<TraverseNode> varlist;
|
||||||
list<PcodeOp *>::const_iterator iter;
|
list<PcodeOp *>::const_iterator iter;
|
||||||
const Varnode *vn,*subvn;
|
const Varnode *vn,*subvn;
|
||||||
const PcodeOp *op;
|
const PcodeOp *op;
|
||||||
int4 i;
|
int4 i;
|
||||||
bool res = true;
|
bool res = true;
|
||||||
|
|
||||||
|
varlist.reserve(64);
|
||||||
invn->setMark(); // Marks prevent infinite loops
|
invn->setMark(); // Marks prevent infinite loops
|
||||||
varlist.push_back(invn);
|
varlist.emplace_back(invn,mainFlags);
|
||||||
|
|
||||||
i = 0;
|
for(i=0;i < varlist.size();++i) {
|
||||||
while(i < varlist.size()) {
|
vn = varlist[i].vn;
|
||||||
vn = varlist[i++];
|
uint4 baseFlags = varlist[i].flags;
|
||||||
for(iter=vn->descend.begin();iter!=vn->descend.end();++iter) {
|
for(iter=vn->descend.begin();iter!=vn->descend.end();++iter) {
|
||||||
op = *iter;
|
op = *iter;
|
||||||
if (op == opmatch) {
|
if (op == opmatch) {
|
||||||
if (op->getIn(trial.getSlot())==vn) continue;
|
if (op->getIn(trial.getSlot())==vn) continue;
|
||||||
}
|
}
|
||||||
|
uint4 curFlags = baseFlags;
|
||||||
switch(op->code()) {
|
switch(op->code()) {
|
||||||
case CPUI_BRANCH: // These ops define a USE of a variable
|
case CPUI_BRANCH: // These ops define a USE of a variable
|
||||||
case CPUI_CBRANCH:
|
case CPUI_CBRANCH:
|
||||||
|
@ -1555,17 +1589,39 @@ bool Funcdata::onlyOpUse(const Varnode *invn,const PcodeOp *opmatch,const ParamT
|
||||||
break;
|
break;
|
||||||
case CPUI_CALL:
|
case CPUI_CALL:
|
||||||
case CPUI_CALLIND:
|
case CPUI_CALLIND:
|
||||||
if (checkCallDoubleUse(opmatch,op,vn,trial)) continue;
|
if (checkCallDoubleUse(opmatch,op,vn,curFlags,trial)) continue;
|
||||||
res = false;
|
res = false;
|
||||||
break;
|
break;
|
||||||
|
case CPUI_INDIRECT:
|
||||||
|
curFlags |= Funcdata::traverse_indirectalt;
|
||||||
|
break;
|
||||||
|
case CPUI_COPY:
|
||||||
|
if ((op->getOut()->getSpace()->getType()!=IPTR_INTERNAL)&&!op->isIncidentalCopy()&&!vn->isIncidentalCopy()) {
|
||||||
|
curFlags |= Funcdata::traverse_actionalt;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case CPUI_RETURN:
|
case CPUI_RETURN:
|
||||||
if (opmatch->code()==CPUI_RETURN) { // Are we in a different return
|
if (opmatch->code()==CPUI_RETURN) { // Are we in a different return
|
||||||
if (op->getIn(trial.getSlot())==vn) // But at the same slot
|
if (op->getIn(trial.getSlot())==vn) // But at the same slot
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
else if (activeoutput != (ParamActive *)0) { // Are we in the middle of analyzing returns
|
||||||
|
if (op->getIn(0) != vn) { // Unless we hold actual return value
|
||||||
|
if (!isAlternatePathValid(vn,curFlags))
|
||||||
|
continue; // Don't consider this a "use"
|
||||||
|
}
|
||||||
|
}
|
||||||
res = false;
|
res = false;
|
||||||
break;
|
break;
|
||||||
|
case CPUI_MULTIEQUAL:
|
||||||
|
case CPUI_PIECE:
|
||||||
|
case CPUI_SUBPIECE:
|
||||||
|
case CPUI_INT_SEXT:
|
||||||
|
case CPUI_INT_ZEXT:
|
||||||
|
case CPUI_CAST:
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
|
curFlags |= Funcdata::traverse_actionalt;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!res) break;
|
if (!res) break;
|
||||||
|
@ -1576,7 +1632,7 @@ bool Funcdata::onlyOpUse(const Varnode *invn,const PcodeOp *opmatch,const ParamT
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!subvn->isMark()) {
|
if (!subvn->isMark()) {
|
||||||
varlist.push_back(subvn);
|
varlist.emplace_back(subvn,curFlags);
|
||||||
subvn->setMark();
|
subvn->setMark();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1584,7 +1640,7 @@ bool Funcdata::onlyOpUse(const Varnode *invn,const PcodeOp *opmatch,const ParamT
|
||||||
if (!res) break;
|
if (!res) break;
|
||||||
}
|
}
|
||||||
for(i=0;i<varlist.size();++i)
|
for(i=0;i<varlist.size();++i)
|
||||||
varlist[i]->clearMark();
|
varlist[i].vn->clearMark();
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1596,9 +1652,10 @@ bool Funcdata::onlyOpUse(const Varnode *invn,const PcodeOp *opmatch,const ParamT
|
||||||
/// \param invn is the given trial Varnode to test
|
/// \param invn is the given trial Varnode to test
|
||||||
/// \param op is the given CALL or RETURN
|
/// \param op is the given CALL or RETURN
|
||||||
/// \param trial is the associated parameter trial object
|
/// \param trial is the associated parameter trial object
|
||||||
|
/// \param mainFlags describes traversals along the path from \e invn to \e op
|
||||||
/// \return \b true if the Varnode is only used for the CALL/RETURN
|
/// \return \b true if the Varnode is only used for the CALL/RETURN
|
||||||
bool Funcdata::ancestorOpUse(int4 maxlevel,const Varnode *invn,
|
bool Funcdata::ancestorOpUse(int4 maxlevel,const Varnode *invn,
|
||||||
const PcodeOp *op,ParamTrial &trial) const
|
const PcodeOp *op,ParamTrial &trial,uint4 mainFlags) const
|
||||||
|
|
||||||
{
|
{
|
||||||
int4 i;
|
int4 i;
|
||||||
|
@ -1610,7 +1667,7 @@ bool Funcdata::ancestorOpUse(int4 maxlevel,const Varnode *invn,
|
||||||
if (!invn->isTypeLock()) return false;
|
if (!invn->isTypeLock()) return false;
|
||||||
// If the input is typelocked
|
// If the input is typelocked
|
||||||
// this is as good as being written
|
// this is as good as being written
|
||||||
return onlyOpUse(invn,op,trial); // Test if varnode is only used in op
|
return onlyOpUse(invn,op,trial,mainFlags); // Test if varnode is only used in op
|
||||||
}
|
}
|
||||||
|
|
||||||
const PcodeOp *def = invn->getDef();
|
const PcodeOp *def = invn->getDef();
|
||||||
|
@ -1620,7 +1677,7 @@ bool Funcdata::ancestorOpUse(int4 maxlevel,const Varnode *invn,
|
||||||
// as an "only use"
|
// as an "only use"
|
||||||
if (def->isIndirectCreation())
|
if (def->isIndirectCreation())
|
||||||
return false;
|
return false;
|
||||||
return ancestorOpUse(maxlevel-1,def->getIn(0),op,trial);
|
return ancestorOpUse(maxlevel-1,def->getIn(0),op,trial,mainFlags | Funcdata::traverse_indirect);
|
||||||
case CPUI_MULTIEQUAL:
|
case CPUI_MULTIEQUAL:
|
||||||
// Check if there is any ancestor whose only
|
// Check if there is any ancestor whose only
|
||||||
// use is in this op
|
// use is in this op
|
||||||
|
@ -1628,7 +1685,7 @@ bool Funcdata::ancestorOpUse(int4 maxlevel,const Varnode *invn,
|
||||||
def->setMark(); // Mark that this MULTIEQUAL is on the path
|
def->setMark(); // Mark that this MULTIEQUAL is on the path
|
||||||
// Note: onlyOpUse is using Varnode::setMark
|
// Note: onlyOpUse is using Varnode::setMark
|
||||||
for(i=0;i<def->numInput();++i) {
|
for(i=0;i<def->numInput();++i) {
|
||||||
if (ancestorOpUse(maxlevel-1,def->getIn(i),op,trial)) {
|
if (ancestorOpUse(maxlevel-1,def->getIn(i),op,trial, mainFlags)) {
|
||||||
def->clearMark();
|
def->clearMark();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1637,13 +1694,12 @@ bool Funcdata::ancestorOpUse(int4 maxlevel,const Varnode *invn,
|
||||||
return false;
|
return false;
|
||||||
case CPUI_COPY:
|
case CPUI_COPY:
|
||||||
if ((invn->getSpace()->getType()==IPTR_INTERNAL)||def->isIncidentalCopy()||def->getIn(0)->isIncidentalCopy()) {
|
if ((invn->getSpace()->getType()==IPTR_INTERNAL)||def->isIncidentalCopy()||def->getIn(0)->isIncidentalCopy()) {
|
||||||
if (!ancestorOpUse(maxlevel-1,def->getIn(0),op,trial)) return false;
|
return ancestorOpUse(maxlevel-1,def->getIn(0),op,trial,mainFlags);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CPUI_PIECE:
|
case CPUI_PIECE:
|
||||||
// Concatenation tends to be artificial, so recurse through the least significant part
|
// Concatenation tends to be artificial, so recurse through the least significant part
|
||||||
return ancestorOpUse(maxlevel-1,def->getIn(1),op,trial);
|
return ancestorOpUse(maxlevel-1,def->getIn(1),op,trial,mainFlags);
|
||||||
case CPUI_SUBPIECE:
|
case CPUI_SUBPIECE:
|
||||||
// This is a rather kludgy way to get around where a DIV (or other similar) instruction
|
// This is a rather kludgy way to get around where a DIV (or other similar) instruction
|
||||||
// causes a register that looks like the high precision piece of the function return
|
// causes a register that looks like the high precision piece of the function return
|
||||||
|
@ -1664,7 +1720,7 @@ bool Funcdata::ancestorOpUse(int4 maxlevel,const Varnode *invn,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// This varnode must be top ancestor at this point
|
// This varnode must be top ancestor at this point
|
||||||
return onlyOpUse(invn,op,trial); // Test if varnode is only used in op
|
return onlyOpUse(invn,op,trial,mainFlags); // Test if varnode is only used in op
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \return \b true if there are two input flows, one of which is a normal \e solid flow
|
/// \return \b true if there are two input flows, one of which is a normal \e solid flow
|
||||||
|
|
|
@ -130,6 +130,45 @@ FlowBlock *PriorityQueue::extract(void)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Initialize heritage state information for a particular address space
|
||||||
|
/// \param spc is the address space
|
||||||
|
HeritageInfo::HeritageInfo(AddrSpace *spc)
|
||||||
|
|
||||||
|
{
|
||||||
|
if (spc == (AddrSpace *)0) {
|
||||||
|
space = (AddrSpace *)0;
|
||||||
|
delay = 0;
|
||||||
|
deadcodedelay = 0;
|
||||||
|
hasCallPlaceholders = false;
|
||||||
|
}
|
||||||
|
else if (!spc->isHeritaged()) {
|
||||||
|
space = (AddrSpace *)0;
|
||||||
|
delay = spc->getDelay();
|
||||||
|
deadcodedelay = spc->getDeadcodeDelay();
|
||||||
|
hasCallPlaceholders = false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
space = spc;
|
||||||
|
delay = spc->getDelay();
|
||||||
|
deadcodedelay = spc->getDeadcodeDelay();
|
||||||
|
hasCallPlaceholders = (spc->getType() == IPTR_SPACEBASE);
|
||||||
|
}
|
||||||
|
deadremoved = 0;
|
||||||
|
warningissued = false;
|
||||||
|
loadGuardSearch = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HeritageInfo::reset(void)
|
||||||
|
|
||||||
|
{
|
||||||
|
// Leave any override intact: deadcodedelay = delay;
|
||||||
|
deadremoved = 0;
|
||||||
|
if (space != (AddrSpace *)0)
|
||||||
|
hasCallPlaceholders = (space->getType() == IPTR_SPACEBASE);
|
||||||
|
warningissued = false;
|
||||||
|
loadGuardSearch = false;
|
||||||
|
}
|
||||||
|
|
||||||
/// Instantiate the heritage manager for a particular function.
|
/// Instantiate the heritage manager for a particular function.
|
||||||
/// \param data is the function
|
/// \param data is the function
|
||||||
Heritage::Heritage(Funcdata *data)
|
Heritage::Heritage(Funcdata *data)
|
||||||
|
@ -1180,17 +1219,11 @@ void Heritage::guardCalls(uint4 flags,const Address &addr,int4 size,vector<Varno
|
||||||
uintb off = addr.getOffset();
|
uintb off = addr.getOffset();
|
||||||
bool tryregister = true;
|
bool tryregister = true;
|
||||||
if (spc->getType() == IPTR_SPACEBASE) {
|
if (spc->getType() == IPTR_SPACEBASE) {
|
||||||
if (fc->getStackPlaceholderSlot() < 0) { // Any stack resolution is complete (or never started)
|
|
||||||
if (fc->getSpacebaseOffset() != FuncCallSpecs::offset_unknown)
|
if (fc->getSpacebaseOffset() != FuncCallSpecs::offset_unknown)
|
||||||
off = spc->wrapOffset(off - fc->getSpacebaseOffset());
|
off = spc->wrapOffset(off - fc->getSpacebaseOffset());
|
||||||
else
|
else
|
||||||
tryregister = false; // Do not attempt to register this stack loc as a trial
|
tryregister = false; // Do not attempt to register this stack loc as a trial
|
||||||
}
|
}
|
||||||
else { // Stack has not been resolved, so we need to abort
|
|
||||||
fc->abortSpacebaseRelative(*fd);
|
|
||||||
tryregister = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Address transAddr(spc,off); // Address relative to callee's stack
|
Address transAddr(spc,off); // Address relative to callee's stack
|
||||||
if (tryregister) {
|
if (tryregister) {
|
||||||
int4 inputCharacter = fc->characterizeAsInputParam(transAddr,size);
|
int4 inputCharacter = fc->characterizeAsInputParam(transAddr,size);
|
||||||
|
@ -1695,6 +1728,19 @@ static void verify_dfs(const vector<FlowBlock *> &list,vector<vector<FlowBlock *
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/// Assuming we are just about to do heritage on an address space,
|
||||||
|
/// clear any placeholder LOADs associated with it on CALLs.
|
||||||
|
/// \param info is state for the specific address space
|
||||||
|
void Heritage::clearStackPlaceholders(HeritageInfo *info)
|
||||||
|
|
||||||
|
{
|
||||||
|
int4 numCalls = fd->numCalls();
|
||||||
|
for(int4 i=0;i<numCalls;++i) {
|
||||||
|
fd->getCallSpecs(i)->abortSpacebaseRelative(*fd);
|
||||||
|
}
|
||||||
|
info->hasCallPlaceholders = false; // Mark that clear has taken place
|
||||||
|
}
|
||||||
|
|
||||||
/// \brief Perform one level of Varnode splitting to match a JoinRecord
|
/// \brief Perform one level of Varnode splitting to match a JoinRecord
|
||||||
///
|
///
|
||||||
/// Split all the pieces in \b lastcombo, putting them into \b nextlev in order,
|
/// Split all the pieces in \b lastcombo, putting them into \b nextlev in order,
|
||||||
|
@ -2288,16 +2334,9 @@ void Heritage::buildInfoList(void)
|
||||||
{
|
{
|
||||||
if (!infolist.empty()) return;
|
if (!infolist.empty()) return;
|
||||||
const AddrSpaceManager *manage = fd->getArch();
|
const AddrSpaceManager *manage = fd->getArch();
|
||||||
infolist.resize(manage->numSpaces());
|
infolist.reserve(manage->numSpaces());
|
||||||
for(int4 i=0;i<manage->numSpaces();++i) {
|
for(int4 i=0;i<manage->numSpaces();++i)
|
||||||
AddrSpace *spc = manage->getSpace(i);
|
infolist.emplace_back(manage->getSpace(i));
|
||||||
if (spc == (AddrSpace *)0)
|
|
||||||
infolist[i].set((AddrSpace *)0,0,0);
|
|
||||||
else if (!spc->isHeritaged())
|
|
||||||
infolist[i].set((AddrSpace *)0,spc->getDelay(),spc->getDeadcodeDelay());
|
|
||||||
else
|
|
||||||
infolist[i].set(spc,spc->getDelay(),spc->getDeadcodeDelay());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// From any address space that is active for this pass, free Varnodes are collected
|
/// From any address space that is active for this pass, free Varnodes are collected
|
||||||
|
@ -2328,6 +2367,9 @@ void Heritage::heritage(void)
|
||||||
info = &infolist[i];
|
info = &infolist[i];
|
||||||
if (!info->isHeritaged()) continue;
|
if (!info->isHeritaged()) continue;
|
||||||
if (pass < info->delay) continue; // It is too soon to heritage this space
|
if (pass < info->delay) continue; // It is too soon to heritage this space
|
||||||
|
if (info->hasCallPlaceholders)
|
||||||
|
clearStackPlaceholders(info);
|
||||||
|
|
||||||
if (!info->loadGuardSearch) {
|
if (!info->loadGuardSearch) {
|
||||||
info->loadGuardSearch = true;
|
info->loadGuardSearch = true;
|
||||||
if (discoverIndexedStackPointers(info->space,freeStores,true)) {
|
if (discoverIndexedStackPointers(info->space,freeStores,true)) {
|
||||||
|
|
|
@ -90,11 +90,11 @@ class HeritageInfo {
|
||||||
int4 deadremoved; ///< >0 if Varnodes in this space have been eliminated
|
int4 deadremoved; ///< >0 if Varnodes in this space have been eliminated
|
||||||
bool loadGuardSearch; ///< \b true if the search for LOAD ops to guard has been performed
|
bool loadGuardSearch; ///< \b true if the search for LOAD ops to guard has been performed
|
||||||
bool warningissued; ///< \b true if warning issued previously
|
bool warningissued; ///< \b true if warning issued previously
|
||||||
void set(AddrSpace *spc,int4 dl,int4 dcdl) {
|
bool hasCallPlaceholders; ///< \b true for the \e stack space, if stack placeholders have not been removed
|
||||||
space=spc; delay=dl; deadcodedelay=dcdl; deadremoved=0; warningissued=false; loadGuardSearch = false; } ///< Set all fields
|
|
||||||
bool isHeritaged(void) const { return (space != (AddrSpace *)0); } ///< Return \b true if heritage is performed on this space
|
bool isHeritaged(void) const { return (space != (AddrSpace *)0); } ///< Return \b true if heritage is performed on this space
|
||||||
void reset(void) {
|
void reset(void); ///< Reset the state
|
||||||
deadremoved = 0; deadcodedelay = delay; warningissued = false; loadGuardSearch = false; } ///< Reset
|
public:
|
||||||
|
HeritageInfo(AddrSpace *spc); ///< Constructor
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \brief Description of a LOAD operation that needs to be guarded
|
/// \brief Description of a LOAD operation that needs to be guarded
|
||||||
|
@ -222,6 +222,7 @@ class Heritage {
|
||||||
/// \brief Get the heritage status for the given address space
|
/// \brief Get the heritage status for the given address space
|
||||||
const HeritageInfo *getInfo(AddrSpace *spc) const { return &(infolist[spc->getIndex()]); }
|
const HeritageInfo *getInfo(AddrSpace *spc) const { return &(infolist[spc->getIndex()]); }
|
||||||
|
|
||||||
|
void clearStackPlaceholders(HeritageInfo *info); ///< Clear remaining stack placeholder LOADs on any call
|
||||||
void splitJoinLevel(vector<Varnode *> &lastcombo,vector<Varnode *> &nextlev,JoinRecord *joinrec);
|
void splitJoinLevel(vector<Varnode *> &lastcombo,vector<Varnode *> &nextlev,JoinRecord *joinrec);
|
||||||
void splitJoinRead(Varnode *vn,JoinRecord *joinrec);
|
void splitJoinRead(Varnode *vn,JoinRecord *joinrec);
|
||||||
void splitJoinWrite(Varnode *vn,JoinRecord *joinrec);
|
void splitJoinWrite(Varnode *vn,JoinRecord *joinrec);
|
||||||
|
|
|
@ -376,6 +376,13 @@ public:
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// \brief Node for a forward traversal of a Varnode expression
|
||||||
|
struct TraverseNode {
|
||||||
|
const Varnode *vn; ///< Varnode at the point of traversal
|
||||||
|
uint4 flags; ///< Flags associated with the node
|
||||||
|
TraverseNode(const Varnode *v,uint4 f) { vn = v; flags = f; }
|
||||||
|
};
|
||||||
|
|
||||||
bool contiguous_test(Varnode *vn1,Varnode *vn2); ///< Test if Varnodes are pieces of a whole
|
bool contiguous_test(Varnode *vn1,Varnode *vn2); ///< Test if Varnodes are pieces of a whole
|
||||||
Varnode *findContiguousWhole(Funcdata &data,Varnode *vn1,
|
Varnode *findContiguousWhole(Funcdata &data,Varnode *vn1,
|
||||||
Varnode *vn2); ///< Retrieve the whole Varnode given pieces
|
Varnode *vn2); ///< Retrieve the whole Varnode given pieces
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
<decompilertest>
|
||||||
|
<binaryimage arch="x86:LE:64:default:gcc">
|
||||||
|
<!--
|
||||||
|
Contrived example that seems to set up multiple return value sizes.
|
||||||
|
This used to make the decompiler enter an infinite loop.
|
||||||
|
-->
|
||||||
|
<bytechunk space="ram" offset="0x100000" readonly="true">
|
||||||
|
4883ec1864488b042528000000488944
|
||||||
|
240831c083fe01744f83fe02742a897c
|
||||||
|
2404488d7c2404e8dc0f00008b442404
|
||||||
|
488b542408644833142528000000753d
|
||||||
|
4883c418c3000000488d7c2404b8e903
|
||||||
|
00006689442404e8ac0f00008b442404
|
||||||
|
ebce000000000000488d7c2404c64424
|
||||||
|
0461e8910f00008b442404ebb3e88e0f
|
||||||
|
0000
|
||||||
|
</bytechunk>
|
||||||
|
</binaryimage>
|
||||||
|
<script>
|
||||||
|
<com>map fun r0x100000 getval</com>
|
||||||
|
<com>override flow r0x10007d callreturn</com>
|
||||||
|
<com>lo fu getval</com>
|
||||||
|
<com>decompile</com>
|
||||||
|
<com>print C</com>
|
||||||
|
<com>quit</com>
|
||||||
|
</script>
|
||||||
|
<stringmatch name="Multi-size return #1" min="1" max="1">Stack20 = CONCAT31.*0x61</stringmatch>
|
||||||
|
<stringmatch name="Multi-size return #2" min="1" max="1">Stack20 = CONCAT22.*0x3e9</stringmatch>
|
||||||
|
<stringmatch name="Multi-size return #3" min="1" max="1">Stack20 = param_1</stringmatch>
|
||||||
|
</decompilertest>
|
|
@ -2508,6 +2508,17 @@
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
<varlistentry id="GeneralMaxInstruction">
|
||||||
|
<term><emphasis role="bold">Max Instructions per Function</emphasis></term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
This option sets a maximum number of machine instructions that the decompiler will attempt
|
||||||
|
to analyze for a single function, as a safeguard against analyzing a long sequence
|
||||||
|
of zeroes or other constant data. The decompiler will quickly throw an exception if it
|
||||||
|
traces control-flow into more than the indicated number of instructions.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
</variablelist>
|
</variablelist>
|
||||||
</informalexample>
|
</informalexample>
|
||||||
</para>
|
</para>
|
||||||
|
|
|
@ -75,21 +75,21 @@ public class DecompileOptions {
|
||||||
private final static String IGNOREUNIMPL_OPTIONDESCRIPTION =
|
private final static String IGNOREUNIMPL_OPTIONDESCRIPTION =
|
||||||
"If set, instructions which do not have a p-code translation implemented are " +
|
"If set, instructions which do not have a p-code translation implemented are " +
|
||||||
"treated as if they do nothing (like a NOP)";
|
"treated as if they do nothing (like a NOP)";
|
||||||
private final static boolean IGNOREUNIMPL_OPTIONDEFAULT = false;
|
private final static boolean IGNOREUNIMPL_OPTIONDEFAULT = false; // Must match Architecture::resetDefaultsInternal
|
||||||
private boolean ignoreunimpl;
|
private boolean ignoreunimpl;
|
||||||
|
|
||||||
private final static String INFERCONSTPTR_OPTIONSTRING = "Analysis.Infer constant pointers";
|
private final static String INFERCONSTPTR_OPTIONSTRING = "Analysis.Infer constant pointers";
|
||||||
private final static String INFERCONSTPTR_OPTIONDESCRIPTION =
|
private final static String INFERCONSTPTR_OPTIONDESCRIPTION =
|
||||||
"If set, constants which are not being explicitly used as pointers, but which can be interpreted " +
|
"If set, constants which are not being explicitly used as pointers, but which can be interpreted " +
|
||||||
"as a legitimate address, will still be treated as having a pointer datatype";
|
"as a legitimate address, will still be treated as having a pointer datatype";
|
||||||
private final static boolean INFERCONSTPTR_OPTIONDEFAULT = true;
|
private final static boolean INFERCONSTPTR_OPTIONDEFAULT = true; // Must match Architecture::resetDefaultsInternal
|
||||||
private boolean inferconstptr;
|
private boolean inferconstptr;
|
||||||
|
|
||||||
private final static String ANALYZEFORLOOPS_OPTIONSTRING = "Analysis.Recover -for- loops";
|
private final static String ANALYZEFORLOOPS_OPTIONSTRING = "Analysis.Recover -for- loops";
|
||||||
private final static String ANALYZEFORLOOPS_OPTIONDESCRIPTION =
|
private final static String ANALYZEFORLOOPS_OPTIONDESCRIPTION =
|
||||||
"If set, the decompiler attempts to recover for-loop variables, including their initializer, condition, " +
|
"If set, the decompiler attempts to recover for-loop variables, including their initializer, condition, " +
|
||||||
"and incrementer statements. Loop variable bounds are displayed as a formal -for- loop header";
|
"and incrementer statements. Loop variable bounds are displayed as a formal -for- loop header";
|
||||||
private final static boolean ANALYZEFORLOOPS_OPTIONDEFAULT = true;
|
private final static boolean ANALYZEFORLOOPS_OPTIONDEFAULT = true; // Must match Architecture::resetDefaultsInternal
|
||||||
private boolean analyzeForLoops;
|
private boolean analyzeForLoops;
|
||||||
|
|
||||||
private final static String NULLTOKEN_OPTIONSTRING = "Display.Print 'NULL' for null pointers";
|
private final static String NULLTOKEN_OPTIONSTRING = "Display.Print 'NULL' for null pointers";
|
||||||
|
@ -97,7 +97,7 @@ public class DecompileOptions {
|
||||||
"If set, any zero valued pointer (null pointer) will " +
|
"If set, any zero valued pointer (null pointer) will " +
|
||||||
"be printed using the token 'NULL'. Otherwise, a cast " +
|
"be printed using the token 'NULL'. Otherwise, a cast " +
|
||||||
"of the number '0' is printed.";
|
"of the number '0' is printed.";
|
||||||
private final static boolean NULLTOKEN_OPTIONDEFAULT = false;
|
private final static boolean NULLTOKEN_OPTIONDEFAULT = false; // Must match PrintC::resetDefaultsPrintC
|
||||||
private boolean nullToken;
|
private boolean nullToken;
|
||||||
|
|
||||||
private final static String INPLACEOP_OPTIONSTRING =
|
private final static String INPLACEOP_OPTIONSTRING =
|
||||||
|
@ -105,7 +105,7 @@ public class DecompileOptions {
|
||||||
private final static String INPLACEOP_OPTIONDESCRIPTION =
|
private final static String INPLACEOP_OPTIONDESCRIPTION =
|
||||||
"If set the inplace assignment operators will be used " +
|
"If set the inplace assignment operators will be used " +
|
||||||
"for appropriate expressions. '+=' '*=' '&=' '<<=' etc.";
|
"for appropriate expressions. '+=' '*=' '&=' '<<=' etc.";
|
||||||
private final static boolean INPLACEOP_OPTIONDEFAULT = false;
|
private final static boolean INPLACEOP_OPTIONDEFAULT = false; // Must match PrintC::resetDefaultsPrintC
|
||||||
private boolean inplaceTokens;
|
private boolean inplaceTokens;
|
||||||
|
|
||||||
private final static String ALIASBLOCK_OPTIONSTRING = "Analysis.Alias Blocking";
|
private final static String ALIASBLOCK_OPTIONSTRING = "Analysis.Alias Blocking";
|
||||||
|
@ -137,40 +137,40 @@ public class DecompileOptions {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final static AliasBlockEnum ALIASBLOCK_OPTIONDEFAULT = AliasBlockEnum.Array;
|
private final static AliasBlockEnum ALIASBLOCK_OPTIONDEFAULT = AliasBlockEnum.Array; // Must match Architecture::resetDefaultsInternal
|
||||||
private AliasBlockEnum aliasBlock;
|
private AliasBlockEnum aliasBlock;
|
||||||
|
|
||||||
private final static String CONVENTION_OPTIONSTRING = "Display.Print calling convention name";
|
private final static String CONVENTION_OPTIONSTRING = "Display.Print calling convention name";
|
||||||
private final static String CONVENTION_OPTIONDESCRIPTION =
|
private final static String CONVENTION_OPTIONDESCRIPTION =
|
||||||
"If set, the names of callling conventions (which differ " +
|
"If set, the names of callling conventions (which differ " +
|
||||||
"from the default) will be printed as part of the function prototype.";
|
"from the default) will be printed as part of the function prototype.";
|
||||||
private final static boolean CONVENTION_OPTIONDEFAULT = true;
|
private final static boolean CONVENTION_OPTIONDEFAULT = true; // Must match PrintC::resetDefaultsPrintC
|
||||||
private boolean conventionPrint;
|
private boolean conventionPrint;
|
||||||
|
|
||||||
private final static String NOCAST_OPTIONSTRING = "Display.Disable printing of type casts";
|
private final static String NOCAST_OPTIONSTRING = "Display.Disable printing of type casts";
|
||||||
private final static String NOCAST_OPTIONDESCRIPTION =
|
private final static String NOCAST_OPTIONDESCRIPTION =
|
||||||
"If set, any C style type cast recovered by the decompiler will not be displayed. " +
|
"If set, any C style type cast recovered by the decompiler will not be displayed. " +
|
||||||
"The resulting C syntax may not parse correctly.";
|
"The resulting C syntax may not parse correctly.";
|
||||||
private final static boolean NOCAST_OPTIONDEFAULT = false;
|
private final static boolean NOCAST_OPTIONDEFAULT = false; // Must match PrintC::resetDefaultsPrintC
|
||||||
private boolean noCastPrint;
|
private boolean noCastPrint;
|
||||||
|
|
||||||
private final static String MAXWIDTH_OPTIONSTRING = "Display.Maximum characters in a code line";
|
private final static String MAXWIDTH_OPTIONSTRING = "Display.Maximum characters in a code line";
|
||||||
private final static String MAXWIDTH_OPTIONDESCRIPTION =
|
private final static String MAXWIDTH_OPTIONDESCRIPTION =
|
||||||
"Maximum number of characters allowed per line before " + "before line breaks are forced.";
|
"Maximum number of characters allowed per line before " + "before line breaks are forced.";
|
||||||
private final static int MAXWIDTH_OPTIONDEFAULT = 100;
|
private final static int MAXWIDTH_OPTIONDEFAULT = 100; // Must match EmitPrettyPrint::resetDefaultsPrettyPrint
|
||||||
private int maxwidth;
|
private int maxwidth;
|
||||||
|
|
||||||
private final static String INDENTWIDTH_OPTIONSTRING =
|
private final static String INDENTWIDTH_OPTIONSTRING =
|
||||||
"Display.Number of characters per indent level";
|
"Display.Number of characters per indent level";
|
||||||
private final static String INDENTWIDTH_OPTIONDESCRIPTION =
|
private final static String INDENTWIDTH_OPTIONDESCRIPTION =
|
||||||
"Number of characters indented for each level of control-flow " + "or scope nesting";
|
"Number of characters indented for each level of control-flow " + "or scope nesting";
|
||||||
private final static int INDENTWIDTH_OPTIONDEFAULT = 2;
|
private final static int INDENTWIDTH_OPTIONDEFAULT = 2; // Must match EmitXml::resetDefaultsInternal
|
||||||
private int indentwidth;
|
private int indentwidth;
|
||||||
|
|
||||||
private final static String COMMENTINDENT_OPTIONSTRING = "Display.Comment line indent level";
|
private final static String COMMENTINDENT_OPTIONSTRING = "Display.Comment line indent level";
|
||||||
private final static String COMMENTINDENT_OPTIONDESCRIPTION =
|
private final static String COMMENTINDENT_OPTIONDESCRIPTION =
|
||||||
"Number of characters each line of comments is indented";
|
"Number of characters each line of comments is indented";
|
||||||
private final static int COMMENTINDENT_OPTIONDEFAULT = 20;
|
private final static int COMMENTINDENT_OPTIONDEFAULT = 20; // Must match PrintLanguage::resetDefaultsInternal
|
||||||
private int commentindent;
|
private int commentindent;
|
||||||
|
|
||||||
private final static String COMMENTSTYLE_OPTIONSTRING = "Display.Comment style";
|
private final static String COMMENTSTYLE_OPTIONSTRING = "Display.Comment style";
|
||||||
|
@ -178,6 +178,7 @@ public class DecompileOptions {
|
||||||
"Choice between either the C style comments /* */ or C++ style // ";
|
"Choice between either the C style comments /* */ or C++ style // ";
|
||||||
public static final int SUGGESTED_DECOMPILE_TIMEOUT_SECS = 30;
|
public static final int SUGGESTED_DECOMPILE_TIMEOUT_SECS = 30;
|
||||||
public static final int SUGGESTED_MAX_PAYLOAD_BYTES = 50;
|
public static final int SUGGESTED_MAX_PAYLOAD_BYTES = 50;
|
||||||
|
public static final int SUGGESTED_MAX_INSTRUCTIONS = 100000; // Must match Architecture::resetDefaultsInternal
|
||||||
|
|
||||||
public enum CommentStyleEnum {
|
public enum CommentStyleEnum {
|
||||||
|
|
||||||
|
@ -195,53 +196,51 @@ public class DecompileOptions {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final static CommentStyleEnum COMMENTSTYLE_OPTIONDEFAULT = CommentStyleEnum.CStyle;
|
private final static CommentStyleEnum COMMENTSTYLE_OPTIONDEFAULT = CommentStyleEnum.CStyle; // Must match PrintC::resetDefaultsPrintC
|
||||||
private CommentStyleEnum commentStyle;
|
private CommentStyleEnum commentStyle;
|
||||||
|
|
||||||
private final static String COMMENTPRE_OPTIONSTRING = "Display.Display PRE comments";
|
private final static String COMMENTPRE_OPTIONSTRING = "Display.Display PRE comments";
|
||||||
private final static String COMMENTPRE_OPTIONDESCRIPTION =
|
private final static String COMMENTPRE_OPTIONDESCRIPTION =
|
||||||
"If set, disassembly pre-instruction (PRE) comments are displayed " +
|
"If set, disassembly pre-instruction (PRE) comments are displayed " +
|
||||||
"in the decompiler C output";
|
"in the decompiler C output";
|
||||||
private final static boolean COMMENTPRE_OPTIONDEFAULT = true;
|
private final static boolean COMMENTPRE_OPTIONDEFAULT = true; // Must match PrintLanguage::resetDefaultsInternal
|
||||||
private boolean commentPREInclude;
|
private boolean commentPREInclude;
|
||||||
|
|
||||||
private final static String COMMENTPLATE_OPTIONSTRING = "Display.Display PLATE comments";
|
private final static String COMMENTPLATE_OPTIONSTRING = "Display.Display PLATE comments";
|
||||||
private final static String COMMENTPLATE_OPTIONDESCRIPTION =
|
private final static String COMMENTPLATE_OPTIONDESCRIPTION =
|
||||||
"If set, disassembly plate comments are displayed " + "in the decompiler C output";
|
"If set, disassembly plate comments are displayed " + "in the decompiler C output";
|
||||||
private final static boolean COMMENTPLATE_OPTIONDEFAULT = false;
|
private final static boolean COMMENTPLATE_OPTIONDEFAULT = false; // Must match PrintLanguage::resetDefaultsInternal
|
||||||
private boolean commentPLATEInclude;
|
private boolean commentPLATEInclude;
|
||||||
|
|
||||||
private final static String COMMENTPOST_OPTIONSTRING = "Display.Display POST comments";
|
private final static String COMMENTPOST_OPTIONSTRING = "Display.Display POST comments";
|
||||||
private final static String COMMENTPOST_OPTIONDESCRIPTION =
|
private final static String COMMENTPOST_OPTIONDESCRIPTION =
|
||||||
"If set, disassembly post-instruction (POST) comments are displayed " +
|
"If set, disassembly post-instruction (POST) comments are displayed " +
|
||||||
"in the decompiler C output";
|
"in the decompiler C output";
|
||||||
private final static boolean COMMENTPOST_OPTIONDEFAULT = false;
|
private final static boolean COMMENTPOST_OPTIONDEFAULT = false; // Must match PrintLanguage::resetDefaultsInternal
|
||||||
private boolean commentPOSTInclude;
|
private boolean commentPOSTInclude;
|
||||||
|
|
||||||
private final static String COMMENTEOL_OPTIONSTRING = "Display.Display EOL comments";
|
private final static String COMMENTEOL_OPTIONSTRING = "Display.Display EOL comments";
|
||||||
private final static String COMMENTEOL_OPTIONDESCRIPTION =
|
private final static String COMMENTEOL_OPTIONDESCRIPTION =
|
||||||
"If set, disassembly end-of-line (EOL) comments are displayed " +
|
"If set, disassembly end-of-line (EOL) comments are displayed " +
|
||||||
"in the decompiler C output";
|
"in the decompiler C output";
|
||||||
private final static boolean COMMENTEOL_OPTIONDEFAULT = false;
|
private final static boolean COMMENTEOL_OPTIONDEFAULT = false; // Must match PrintLanguage::resetDefaultsInternal
|
||||||
private boolean commentEOLInclude;
|
private boolean commentEOLInclude;
|
||||||
|
|
||||||
private final static String COMMENTWARN_OPTIONSTRING = "Display.Display Warning comments";
|
private final static String COMMENTWARN_OPTIONSTRING = "Display.Display Warning comments";
|
||||||
private final static String COMMENTWARN_OPTIONDESCRIPTION =
|
private final static String COMMENTWARN_OPTIONDESCRIPTION =
|
||||||
"If set, warnings generated by the decompiler embedded in the displayed " +
|
"If set, warnings generated by the decompiler embedded in the displayed " +
|
||||||
"code as comments";
|
"code as comments";
|
||||||
private final static boolean COMMENTWARN_OPTIONDEFAULT = true;
|
private final static boolean COMMENTWARN_OPTIONDEFAULT = true; // Must match PrintLanguage::resetDefaultsInternal
|
||||||
private boolean commentWARNInclude;
|
private boolean commentWARNInclude;
|
||||||
|
|
||||||
private final static String COMMENTHEAD_OPTIONSTRING = "Display.Display Header comment";
|
private final static String COMMENTHEAD_OPTIONSTRING = "Display.Display Header comment";
|
||||||
private final static String COMMENTHEAD_OPTIONDESCRIPTION =
|
private final static String COMMENTHEAD_OPTIONDESCRIPTION =
|
||||||
"If set, the entry point plate comment is displayed as " + "a function header comment.";
|
"If set, the entry point plate comment is displayed as " + "a function header comment.";
|
||||||
private final static boolean COMMENTHEAD_OPTIONDEFAULT = true;
|
private final static boolean COMMENTHEAD_OPTIONDEFAULT = true; // Must match PrintLanguage::resetDefaultsInternal
|
||||||
private boolean commentHeadInclude;
|
private boolean commentHeadInclude;
|
||||||
|
|
||||||
public enum NamespaceStrategy {
|
public enum NamespaceStrategy {
|
||||||
Minimal("minimal", "Minimally"),
|
Minimal("minimal", "Minimally"), All("all", "Always"), Never("none", "Never");
|
||||||
All("all", "Always"),
|
|
||||||
Never("none", "Never");
|
|
||||||
|
|
||||||
private String label;
|
private String label;
|
||||||
private String optionString;
|
private String optionString;
|
||||||
|
@ -264,7 +263,7 @@ public class DecompileOptions {
|
||||||
private final static String NAMESPACE_OPTIONSTRING = "Display.Display Namespaces";
|
private final static String NAMESPACE_OPTIONSTRING = "Display.Display Namespaces";
|
||||||
private final static String NAMESPACE_OPTIONDESCRIPTION =
|
private final static String NAMESPACE_OPTIONDESCRIPTION =
|
||||||
"Choose how/if namespace tokens should be displayed along with symbol names";
|
"Choose how/if namespace tokens should be displayed along with symbol names";
|
||||||
private final static NamespaceStrategy NAMESPACE_OPTIONDEFAULT = NamespaceStrategy.Minimal;
|
private final static NamespaceStrategy NAMESPACE_OPTIONDEFAULT = NamespaceStrategy.Minimal; // Must match PrintLanguage::resetDefaultsInternal
|
||||||
private NamespaceStrategy namespaceStrategy;
|
private NamespaceStrategy namespaceStrategy;
|
||||||
|
|
||||||
private final static String INTEGERFORMAT_OPTIONSTRING = "Display.Integer format";
|
private final static String INTEGERFORMAT_OPTIONSTRING = "Display.Integer format";
|
||||||
|
@ -295,7 +294,7 @@ public class DecompileOptions {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final static IntegerFormatEnum INTEGERFORMAT_OPTIONDEFAULT = IntegerFormatEnum.BestFit;
|
private final static IntegerFormatEnum INTEGERFORMAT_OPTIONDEFAULT = IntegerFormatEnum.BestFit; // Must match PrintLanguage::resetDefaultsInternal
|
||||||
private IntegerFormatEnum integerFormat;
|
private IntegerFormatEnum integerFormat;
|
||||||
|
|
||||||
private final static Color HIGHLIGHT_MIDDLE_MOUSE_DEF = new Color(255, 255, 0, 128);
|
private final static Color HIGHLIGHT_MIDDLE_MOUSE_DEF = new Color(255, 255, 0, 128);
|
||||||
|
@ -356,10 +355,12 @@ public class DecompileOptions {
|
||||||
private final static String LINE_NUMBER_MSG = "Display.Display Line Numbers";
|
private final static String LINE_NUMBER_MSG = "Display.Display Line Numbers";
|
||||||
private final static String DECOMPILE_TIMEOUT = "Decompiler Timeout (seconds)";
|
private final static String DECOMPILE_TIMEOUT = "Decompiler Timeout (seconds)";
|
||||||
private final static String PAYLOAD_LIMIT = "Decompiler Max-Payload (MBytes)";
|
private final static String PAYLOAD_LIMIT = "Decompiler Max-Payload (MBytes)";
|
||||||
|
private final static String MAX_INSTRUCTIONS = "Max Instructions per Function";
|
||||||
private final static Boolean LINE_NUMBER_DEF = Boolean.TRUE;
|
private final static Boolean LINE_NUMBER_DEF = Boolean.TRUE;
|
||||||
private boolean displayLineNumbers;
|
private boolean displayLineNumbers;
|
||||||
private int decompileTimeoutSeconds;
|
private int decompileTimeoutSeconds;
|
||||||
private int payloadLimitMBytes;
|
private int payloadLimitMBytes;
|
||||||
|
private int maxIntructionsPer;
|
||||||
private int cachedResultsSize;
|
private int cachedResultsSize;
|
||||||
|
|
||||||
private DecompilerLanguage displayLanguage; // Output language displayed by the decompiler
|
private DecompilerLanguage displayLanguage; // Output language displayed by the decompiler
|
||||||
|
@ -407,6 +408,7 @@ public class DecompileOptions {
|
||||||
protoEvalModel = "default";
|
protoEvalModel = "default";
|
||||||
decompileTimeoutSeconds = SUGGESTED_DECOMPILE_TIMEOUT_SECS;
|
decompileTimeoutSeconds = SUGGESTED_DECOMPILE_TIMEOUT_SECS;
|
||||||
payloadLimitMBytes = SUGGESTED_MAX_PAYLOAD_BYTES;
|
payloadLimitMBytes = SUGGESTED_MAX_PAYLOAD_BYTES;
|
||||||
|
maxIntructionsPer = SUGGESTED_MAX_INSTRUCTIONS;
|
||||||
cachedResultsSize = SUGGESTED_CACHED_RESULTS_SIZE;
|
cachedResultsSize = SUGGESTED_CACHED_RESULTS_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -472,6 +474,7 @@ public class DecompileOptions {
|
||||||
displayLineNumbers = opt.getBoolean(LINE_NUMBER_MSG, LINE_NUMBER_DEF);
|
displayLineNumbers = opt.getBoolean(LINE_NUMBER_MSG, LINE_NUMBER_DEF);
|
||||||
decompileTimeoutSeconds = opt.getInt(DECOMPILE_TIMEOUT, SUGGESTED_DECOMPILE_TIMEOUT_SECS);
|
decompileTimeoutSeconds = opt.getInt(DECOMPILE_TIMEOUT, SUGGESTED_DECOMPILE_TIMEOUT_SECS);
|
||||||
payloadLimitMBytes = opt.getInt(PAYLOAD_LIMIT, SUGGESTED_MAX_PAYLOAD_BYTES);
|
payloadLimitMBytes = opt.getInt(PAYLOAD_LIMIT, SUGGESTED_MAX_PAYLOAD_BYTES);
|
||||||
|
maxIntructionsPer = opt.getInt(MAX_INSTRUCTIONS, SUGGESTED_MAX_INSTRUCTIONS);
|
||||||
cachedResultsSize = opt.getInt(CACHED_RESULTS_SIZE_MSG, SUGGESTED_CACHED_RESULTS_SIZE);
|
cachedResultsSize = opt.getInt(CACHED_RESULTS_SIZE_MSG, SUGGESTED_CACHED_RESULTS_SIZE);
|
||||||
|
|
||||||
grabFromToolOptions(ownerPlugin);
|
grabFromToolOptions(ownerPlugin);
|
||||||
|
@ -533,172 +536,132 @@ public class DecompileOptions {
|
||||||
* @param program the program
|
* @param program the program
|
||||||
*/
|
*/
|
||||||
public void registerOptions(Plugin ownerPlugin, ToolOptions opt, Program program) {
|
public void registerOptions(Plugin ownerPlugin, ToolOptions opt, Program program) {
|
||||||
opt.registerOption(PREDICATE_OPTIONSTRING,
|
opt.registerOption(PREDICATE_OPTIONSTRING, PREDICATE_OPTIONDEFAULT,
|
||||||
PREDICATE_OPTIONDEFAULT,
|
|
||||||
new HelpLocation(HelpTopics.DECOMPILER, "AnalysisPredicate"),
|
new HelpLocation(HelpTopics.DECOMPILER, "AnalysisPredicate"),
|
||||||
PREDICATE_OPTIONDESCRIPTION);
|
PREDICATE_OPTIONDESCRIPTION);
|
||||||
opt.registerOption(READONLY_OPTIONSTRING,
|
opt.registerOption(READONLY_OPTIONSTRING, READONLY_OPTIONDEFAULT,
|
||||||
READONLY_OPTIONDEFAULT,
|
|
||||||
new HelpLocation(HelpTopics.DECOMPILER, "AnalysisReadOnly"),
|
new HelpLocation(HelpTopics.DECOMPILER, "AnalysisReadOnly"),
|
||||||
READONLY_OPTIONDESCRIPTION);
|
READONLY_OPTIONDESCRIPTION);
|
||||||
opt.registerOption(ELIMINATE_UNREACHABLE_OPTIONSTRING,
|
opt.registerOption(ELIMINATE_UNREACHABLE_OPTIONSTRING, ELIMINATE_UNREACHABLE_OPTIONDEFAULT,
|
||||||
ELIMINATE_UNREACHABLE_OPTIONDEFAULT,
|
|
||||||
new HelpLocation(HelpTopics.DECOMPILER, "AnalysisUnreachable"),
|
new HelpLocation(HelpTopics.DECOMPILER, "AnalysisUnreachable"),
|
||||||
ELIMINATE_UNREACHABLE_OPTIONDESCRIPTION);
|
ELIMINATE_UNREACHABLE_OPTIONDESCRIPTION);
|
||||||
opt.registerOption(SIMPLIFY_DOUBLEPRECISION_OPTIONSTRING,
|
opt.registerOption(SIMPLIFY_DOUBLEPRECISION_OPTIONSTRING,
|
||||||
SIMPLIFY_DOUBLEPRECISION_OPTIONDEFAULT,
|
SIMPLIFY_DOUBLEPRECISION_OPTIONDEFAULT,
|
||||||
new HelpLocation(HelpTopics.DECOMPILER, "AnalysisExtendedPrecision"),
|
new HelpLocation(HelpTopics.DECOMPILER, "AnalysisExtendedPrecision"),
|
||||||
SIMPLIFY_DOUBLEPRECISION_OPTIONDESCRIPTION);
|
SIMPLIFY_DOUBLEPRECISION_OPTIONDESCRIPTION);
|
||||||
opt.registerOption(IGNOREUNIMPL_OPTIONSTRING,
|
opt.registerOption(IGNOREUNIMPL_OPTIONSTRING, IGNOREUNIMPL_OPTIONDEFAULT,
|
||||||
IGNOREUNIMPL_OPTIONDEFAULT,
|
|
||||||
new HelpLocation(HelpTopics.DECOMPILER, "AnalysisIgnoreUnimplemented"),
|
new HelpLocation(HelpTopics.DECOMPILER, "AnalysisIgnoreUnimplemented"),
|
||||||
IGNOREUNIMPL_OPTIONDESCRIPTION);
|
IGNOREUNIMPL_OPTIONDESCRIPTION);
|
||||||
opt.registerOption(INFERCONSTPTR_OPTIONSTRING,
|
opt.registerOption(INFERCONSTPTR_OPTIONSTRING, INFERCONSTPTR_OPTIONDEFAULT,
|
||||||
INFERCONSTPTR_OPTIONDEFAULT,
|
|
||||||
new HelpLocation(HelpTopics.DECOMPILER, "AnalysisInferConstants"),
|
new HelpLocation(HelpTopics.DECOMPILER, "AnalysisInferConstants"),
|
||||||
INFERCONSTPTR_OPTIONDESCRIPTION);
|
INFERCONSTPTR_OPTIONDESCRIPTION);
|
||||||
opt.registerOption(ANALYZEFORLOOPS_OPTIONSTRING,
|
opt.registerOption(ANALYZEFORLOOPS_OPTIONSTRING, ANALYZEFORLOOPS_OPTIONDEFAULT,
|
||||||
ANALYZEFORLOOPS_OPTIONDEFAULT,
|
|
||||||
new HelpLocation(HelpTopics.DECOMPILER, "AnalysisForLoops"),
|
new HelpLocation(HelpTopics.DECOMPILER, "AnalysisForLoops"),
|
||||||
ANALYZEFORLOOPS_OPTIONDESCRIPTION);
|
ANALYZEFORLOOPS_OPTIONDESCRIPTION);
|
||||||
opt.registerOption(NULLTOKEN_OPTIONSTRING,
|
opt.registerOption(NULLTOKEN_OPTIONSTRING, NULLTOKEN_OPTIONDEFAULT,
|
||||||
NULLTOKEN_OPTIONDEFAULT,
|
new HelpLocation(HelpTopics.DECOMPILER, "DisplayNull"), NULLTOKEN_OPTIONDESCRIPTION);
|
||||||
new HelpLocation(HelpTopics.DECOMPILER, "DisplayNull"),
|
opt.registerOption(INPLACEOP_OPTIONSTRING, INPLACEOP_OPTIONDEFAULT,
|
||||||
NULLTOKEN_OPTIONDESCRIPTION);
|
|
||||||
opt.registerOption(INPLACEOP_OPTIONSTRING,
|
|
||||||
INPLACEOP_OPTIONDEFAULT,
|
|
||||||
new HelpLocation(HelpTopics.DECOMPILER, "AnalysisInPlace"),
|
new HelpLocation(HelpTopics.DECOMPILER, "AnalysisInPlace"),
|
||||||
INPLACEOP_OPTIONDESCRIPTION);
|
INPLACEOP_OPTIONDESCRIPTION);
|
||||||
opt.registerOption(ALIASBLOCK_OPTIONSTRING,
|
opt.registerOption(ALIASBLOCK_OPTIONSTRING, ALIASBLOCK_OPTIONDEFAULT,
|
||||||
ALIASBLOCK_OPTIONDEFAULT,
|
|
||||||
new HelpLocation(HelpTopics.DECOMPILER, "AnalysisAliasBlocking"),
|
new HelpLocation(HelpTopics.DECOMPILER, "AnalysisAliasBlocking"),
|
||||||
ALIASBLOCK_OPTIONDESCRIPTION);
|
ALIASBLOCK_OPTIONDESCRIPTION);
|
||||||
opt.registerOption(CONVENTION_OPTIONSTRING,
|
opt.registerOption(CONVENTION_OPTIONSTRING, CONVENTION_OPTIONDEFAULT,
|
||||||
CONVENTION_OPTIONDEFAULT,
|
|
||||||
new HelpLocation(HelpTopics.DECOMPILER, "DisplayConvention"),
|
new HelpLocation(HelpTopics.DECOMPILER, "DisplayConvention"),
|
||||||
CONVENTION_OPTIONDESCRIPTION);
|
CONVENTION_OPTIONDESCRIPTION);
|
||||||
opt.registerOption(NOCAST_OPTIONSTRING,
|
opt.registerOption(NOCAST_OPTIONSTRING, NOCAST_OPTIONDEFAULT,
|
||||||
NOCAST_OPTIONDEFAULT,
|
|
||||||
new HelpLocation(HelpTopics.DECOMPILER, "DisplayDisableCasts"),
|
new HelpLocation(HelpTopics.DECOMPILER, "DisplayDisableCasts"),
|
||||||
NOCAST_OPTIONDESCRIPTION);
|
NOCAST_OPTIONDESCRIPTION);
|
||||||
opt.registerOption(MAXWIDTH_OPTIONSTRING,
|
opt.registerOption(MAXWIDTH_OPTIONSTRING, MAXWIDTH_OPTIONDEFAULT,
|
||||||
MAXWIDTH_OPTIONDEFAULT,
|
new HelpLocation(HelpTopics.DECOMPILER, "DisplayMaxChar"), MAXWIDTH_OPTIONDESCRIPTION);
|
||||||
new HelpLocation(HelpTopics.DECOMPILER, "DisplayMaxChar"),
|
opt.registerOption(INDENTWIDTH_OPTIONSTRING, INDENTWIDTH_OPTIONDEFAULT,
|
||||||
MAXWIDTH_OPTIONDESCRIPTION);
|
|
||||||
opt.registerOption(INDENTWIDTH_OPTIONSTRING,
|
|
||||||
INDENTWIDTH_OPTIONDEFAULT,
|
|
||||||
new HelpLocation(HelpTopics.DECOMPILER, "DisplayIndentLevel"),
|
new HelpLocation(HelpTopics.DECOMPILER, "DisplayIndentLevel"),
|
||||||
INDENTWIDTH_OPTIONDESCRIPTION);
|
INDENTWIDTH_OPTIONDESCRIPTION);
|
||||||
opt.registerOption(COMMENTINDENT_OPTIONSTRING,
|
opt.registerOption(COMMENTINDENT_OPTIONSTRING, COMMENTINDENT_OPTIONDEFAULT,
|
||||||
COMMENTINDENT_OPTIONDEFAULT,
|
|
||||||
new HelpLocation(HelpTopics.DECOMPILER, "DisplayCommentIndent"),
|
new HelpLocation(HelpTopics.DECOMPILER, "DisplayCommentIndent"),
|
||||||
COMMENTINDENT_OPTIONDESCRIPTION);
|
COMMENTINDENT_OPTIONDESCRIPTION);
|
||||||
opt.registerOption(COMMENTSTYLE_OPTIONSTRING,
|
opt.registerOption(COMMENTSTYLE_OPTIONSTRING, COMMENTSTYLE_OPTIONDEFAULT,
|
||||||
COMMENTSTYLE_OPTIONDEFAULT,
|
|
||||||
new HelpLocation(HelpTopics.DECOMPILER, "DisplayCommentStyle"),
|
new HelpLocation(HelpTopics.DECOMPILER, "DisplayCommentStyle"),
|
||||||
COMMENTSTYLE_OPTIONDESCRIPTION);
|
COMMENTSTYLE_OPTIONDESCRIPTION);
|
||||||
opt.registerOption(COMMENTEOL_OPTIONSTRING,
|
opt.registerOption(COMMENTEOL_OPTIONSTRING, COMMENTEOL_OPTIONDEFAULT,
|
||||||
COMMENTEOL_OPTIONDEFAULT,
|
|
||||||
new HelpLocation(HelpTopics.DECOMPILER, "CommentOptions"),
|
new HelpLocation(HelpTopics.DECOMPILER, "CommentOptions"),
|
||||||
COMMENTEOL_OPTIONDESCRIPTION);
|
COMMENTEOL_OPTIONDESCRIPTION);
|
||||||
opt.registerOption(COMMENTPRE_OPTIONSTRING,
|
opt.registerOption(COMMENTPRE_OPTIONSTRING, COMMENTPRE_OPTIONDEFAULT,
|
||||||
COMMENTPRE_OPTIONDEFAULT,
|
|
||||||
new HelpLocation(HelpTopics.DECOMPILER, "CommentOptions"),
|
new HelpLocation(HelpTopics.DECOMPILER, "CommentOptions"),
|
||||||
COMMENTPRE_OPTIONDESCRIPTION);
|
COMMENTPRE_OPTIONDESCRIPTION);
|
||||||
opt.registerOption(COMMENTPOST_OPTIONSTRING,
|
opt.registerOption(COMMENTPOST_OPTIONSTRING, COMMENTPOST_OPTIONDEFAULT,
|
||||||
COMMENTPOST_OPTIONDEFAULT,
|
|
||||||
new HelpLocation(HelpTopics.DECOMPILER, "CommentOptions"),
|
new HelpLocation(HelpTopics.DECOMPILER, "CommentOptions"),
|
||||||
COMMENTPOST_OPTIONDESCRIPTION);
|
COMMENTPOST_OPTIONDESCRIPTION);
|
||||||
opt.registerOption(COMMENTPLATE_OPTIONSTRING,
|
opt.registerOption(COMMENTPLATE_OPTIONSTRING, COMMENTPLATE_OPTIONDEFAULT,
|
||||||
COMMENTPLATE_OPTIONDEFAULT,
|
|
||||||
new HelpLocation(HelpTopics.DECOMPILER, "CommentOptions"),
|
new HelpLocation(HelpTopics.DECOMPILER, "CommentOptions"),
|
||||||
COMMENTPLATE_OPTIONDESCRIPTION);
|
COMMENTPLATE_OPTIONDESCRIPTION);
|
||||||
opt.registerOption(COMMENTWARN_OPTIONSTRING,
|
opt.registerOption(COMMENTWARN_OPTIONSTRING, COMMENTWARN_OPTIONDEFAULT,
|
||||||
COMMENTWARN_OPTIONDEFAULT,
|
|
||||||
new HelpLocation(HelpTopics.DECOMPILER, "DisplayWarningComments"),
|
new HelpLocation(HelpTopics.DECOMPILER, "DisplayWarningComments"),
|
||||||
COMMENTWARN_OPTIONDESCRIPTION);
|
COMMENTWARN_OPTIONDESCRIPTION);
|
||||||
opt.registerOption(COMMENTHEAD_OPTIONSTRING,
|
opt.registerOption(COMMENTHEAD_OPTIONSTRING, COMMENTHEAD_OPTIONDEFAULT,
|
||||||
COMMENTHEAD_OPTIONDEFAULT,
|
|
||||||
new HelpLocation(HelpTopics.DECOMPILER, "DisplayHeaderComment"),
|
new HelpLocation(HelpTopics.DECOMPILER, "DisplayHeaderComment"),
|
||||||
COMMENTHEAD_OPTIONDESCRIPTION);
|
COMMENTHEAD_OPTIONDESCRIPTION);
|
||||||
opt.registerOption(NAMESPACE_OPTIONSTRING,
|
opt.registerOption(NAMESPACE_OPTIONSTRING, NAMESPACE_OPTIONDEFAULT,
|
||||||
NAMESPACE_OPTIONDEFAULT,
|
|
||||||
new HelpLocation(HelpTopics.DECOMPILER, "DisplayNamespaces"),
|
new HelpLocation(HelpTopics.DECOMPILER, "DisplayNamespaces"),
|
||||||
NAMESPACE_OPTIONDESCRIPTION);
|
NAMESPACE_OPTIONDESCRIPTION);
|
||||||
opt.registerOption(INTEGERFORMAT_OPTIONSTRING,
|
opt.registerOption(INTEGERFORMAT_OPTIONSTRING, INTEGERFORMAT_OPTIONDEFAULT,
|
||||||
INTEGERFORMAT_OPTIONDEFAULT,
|
|
||||||
new HelpLocation(HelpTopics.DECOMPILER, "DisplayIntegerFormat"),
|
new HelpLocation(HelpTopics.DECOMPILER, "DisplayIntegerFormat"),
|
||||||
INTEGERFORMAT_OPTIONDESCRIPTION);
|
INTEGERFORMAT_OPTIONDESCRIPTION);
|
||||||
opt.registerOption(HIGHLIGHT_KEYWORD_MSG,
|
opt.registerOption(HIGHLIGHT_KEYWORD_MSG, HIGHLIGHT_KEYWORD_DEF,
|
||||||
HIGHLIGHT_KEYWORD_DEF,
|
|
||||||
new HelpLocation(HelpTopics.DECOMPILER, "DisplayTokenColor"),
|
new HelpLocation(HelpTopics.DECOMPILER, "DisplayTokenColor"),
|
||||||
"Color used for highlighting keywords.");
|
"Color used for highlighting keywords.");
|
||||||
opt.registerOption(HIGHLIGHT_TYPE_MSG,
|
opt.registerOption(HIGHLIGHT_TYPE_MSG, HIGHLIGHT_TYPE_DEF,
|
||||||
HIGHLIGHT_TYPE_DEF,
|
|
||||||
new HelpLocation(HelpTopics.DECOMPILER, "DisplayTokenColor"),
|
new HelpLocation(HelpTopics.DECOMPILER, "DisplayTokenColor"),
|
||||||
"Color used for highlighting types.");
|
"Color used for highlighting types.");
|
||||||
opt.registerOption(HIGHLIGHT_FUNCTION_MSG,
|
opt.registerOption(HIGHLIGHT_FUNCTION_MSG, HIGHLIGHT_FUNCTION_DEF,
|
||||||
HIGHLIGHT_FUNCTION_DEF,
|
|
||||||
new HelpLocation(HelpTopics.DECOMPILER, "DisplayTokenColor"),
|
new HelpLocation(HelpTopics.DECOMPILER, "DisplayTokenColor"),
|
||||||
"Color used for highlighting function names.");
|
"Color used for highlighting function names.");
|
||||||
opt.registerOption(HIGHLIGHT_COMMENT_MSG,
|
opt.registerOption(HIGHLIGHT_COMMENT_MSG, HIGHLIGHT_COMMENT_DEF,
|
||||||
HIGHLIGHT_COMMENT_DEF,
|
|
||||||
new HelpLocation(HelpTopics.DECOMPILER, "DisplayTokenColor"),
|
new HelpLocation(HelpTopics.DECOMPILER, "DisplayTokenColor"),
|
||||||
"Color used for highlighting comments.");
|
"Color used for highlighting comments.");
|
||||||
opt.registerOption(HIGHLIGHT_VARIABLE_MSG,
|
opt.registerOption(HIGHLIGHT_VARIABLE_MSG, HIGHLIGHT_VARIABLE_DEF,
|
||||||
HIGHLIGHT_VARIABLE_DEF,
|
|
||||||
new HelpLocation(HelpTopics.DECOMPILER, "DisplayTokenColor"),
|
new HelpLocation(HelpTopics.DECOMPILER, "DisplayTokenColor"),
|
||||||
"Color used for highlighting variables.");
|
"Color used for highlighting variables.");
|
||||||
opt.registerOption(HIGHLIGHT_CONST_MSG,
|
opt.registerOption(HIGHLIGHT_CONST_MSG, HIGHLIGHT_CONST_DEF,
|
||||||
HIGHLIGHT_CONST_DEF,
|
|
||||||
new HelpLocation(HelpTopics.DECOMPILER, "DisplayTokenColor"),
|
new HelpLocation(HelpTopics.DECOMPILER, "DisplayTokenColor"),
|
||||||
"Color used for highlighting constants.");
|
"Color used for highlighting constants.");
|
||||||
opt.registerOption(HIGHLIGHT_PARAMETER_MSG,
|
opt.registerOption(HIGHLIGHT_PARAMETER_MSG, HIGHLIGHT_PARAMETER_DEF,
|
||||||
HIGHLIGHT_PARAMETER_DEF,
|
|
||||||
new HelpLocation(HelpTopics.DECOMPILER, "DisplayTokenColor"),
|
new HelpLocation(HelpTopics.DECOMPILER, "DisplayTokenColor"),
|
||||||
"Color used for highlighting parameters.");
|
"Color used for highlighting parameters.");
|
||||||
opt.registerOption(HIGHLIGHT_GLOBAL_MSG,
|
opt.registerOption(HIGHLIGHT_GLOBAL_MSG, HIGHLIGHT_GLOBAL_DEF,
|
||||||
HIGHLIGHT_GLOBAL_DEF,
|
|
||||||
new HelpLocation(HelpTopics.DECOMPILER, "DisplayTokenColor"),
|
new HelpLocation(HelpTopics.DECOMPILER, "DisplayTokenColor"),
|
||||||
"Color used for highlighting global variables.");
|
"Color used for highlighting global variables.");
|
||||||
opt.registerOption(HIGHLIGHT_DEFAULT_MSG,
|
opt.registerOption(HIGHLIGHT_DEFAULT_MSG, HIGHLIGHT_DEFAULT_DEF,
|
||||||
HIGHLIGHT_DEFAULT_DEF,
|
|
||||||
new HelpLocation(HelpTopics.DECOMPILER, "DisplayColorDefault"),
|
new HelpLocation(HelpTopics.DECOMPILER, "DisplayColorDefault"),
|
||||||
"The color used when a specific color is not specified.");
|
"The color used when a specific color is not specified.");
|
||||||
opt.registerOption(CODE_VIEWER_BACKGROUND_COLOR_MSG,
|
opt.registerOption(CODE_VIEWER_BACKGROUND_COLOR_MSG, CODE_VIEWER_BACKGROUND_COLOR,
|
||||||
CODE_VIEWER_BACKGROUND_COLOR,
|
|
||||||
new HelpLocation(HelpTopics.DECOMPILER, "DisplayBackgroundColor"),
|
new HelpLocation(HelpTopics.DECOMPILER, "DisplayBackgroundColor"),
|
||||||
"The background color of the decompiler window.");
|
"The background color of the decompiler window.");
|
||||||
opt.registerOption(FONT_MSG,
|
opt.registerOption(FONT_MSG, DEFAULT_FONT,
|
||||||
DEFAULT_FONT,
|
|
||||||
new HelpLocation(HelpTopics.DECOMPILER, "DisplayFont"),
|
new HelpLocation(HelpTopics.DECOMPILER, "DisplayFont"),
|
||||||
"The font used to render text in the decompiler.");
|
"The font used to render text in the decompiler.");
|
||||||
opt.registerOption(SEARCH_HIGHLIGHT_MSG,
|
opt.registerOption(SEARCH_HIGHLIGHT_MSG, SEARCH_HIGHLIGHT_DEF,
|
||||||
SEARCH_HIGHLIGHT_DEF,
|
|
||||||
new HelpLocation(HelpTopics.DECOMPILER, "DisplayFindHighlight"),
|
new HelpLocation(HelpTopics.DECOMPILER, "DisplayFindHighlight"),
|
||||||
"The color used to highlight matches using the Find Dialog.");
|
"The color used to highlight matches using the Find Dialog.");
|
||||||
opt.registerOption(LINE_NUMBER_MSG,
|
opt.registerOption(LINE_NUMBER_MSG, LINE_NUMBER_DEF,
|
||||||
LINE_NUMBER_DEF,
|
|
||||||
new HelpLocation(HelpTopics.DECOMPILER, "DisplayLineNumbers"),
|
new HelpLocation(HelpTopics.DECOMPILER, "DisplayLineNumbers"),
|
||||||
"Toggle for displaying line numbers in the decompiler.");
|
"Toggle for displaying line numbers in the decompiler.");
|
||||||
opt.registerOption(DECOMPILE_TIMEOUT,
|
opt.registerOption(DECOMPILE_TIMEOUT, SUGGESTED_DECOMPILE_TIMEOUT_SECS,
|
||||||
SUGGESTED_DECOMPILE_TIMEOUT_SECS,
|
|
||||||
new HelpLocation(HelpTopics.DECOMPILER, "GeneralTimeout"),
|
new HelpLocation(HelpTopics.DECOMPILER, "GeneralTimeout"),
|
||||||
"The number of seconds to allow the decompiler to run before terminating the " +
|
"The number of seconds to allow the decompiler to run before terminating the " +
|
||||||
"decompiler.\nCurrently this does not affect the UI, which will run indefinitely. " +
|
"decompiler.\nCurrently this does not affect the UI, which will run indefinitely. " +
|
||||||
"This setting currently only affects background analysis that uses the decompiler.");
|
"This setting currently only affects background analysis that uses the decompiler.");
|
||||||
opt.registerOption(PAYLOAD_LIMIT,
|
opt.registerOption(PAYLOAD_LIMIT, SUGGESTED_MAX_PAYLOAD_BYTES,
|
||||||
SUGGESTED_MAX_PAYLOAD_BYTES,
|
|
||||||
new HelpLocation(HelpTopics.DECOMPILER, "GeneralMaxPayload"),
|
new HelpLocation(HelpTopics.DECOMPILER, "GeneralMaxPayload"),
|
||||||
"The maximum size of the decompiler result payload in MBYtes (Suggested value: 50).");
|
"The maximum size of the decompiler result payload in MBYtes (Suggested value: 50).");
|
||||||
opt.registerOption(HIGHLIGHT_CURRENT_VARIABLE_MSG,
|
opt.registerOption(MAX_INSTRUCTIONS, SUGGESTED_MAX_INSTRUCTIONS,
|
||||||
HIGHLIGHT_CURRENT_VARIABLE_DEF,
|
new HelpLocation(HelpTopics.DECOMPILER, "GeneralMaxInstruction"),
|
||||||
|
"The maximum number of instructions decompiled in a single function");
|
||||||
|
opt.registerOption(HIGHLIGHT_CURRENT_VARIABLE_MSG, HIGHLIGHT_CURRENT_VARIABLE_DEF,
|
||||||
new HelpLocation(HelpTopics.DECOMPILER, "DisplayCurrentHighlight"),
|
new HelpLocation(HelpTopics.DECOMPILER, "DisplayCurrentHighlight"),
|
||||||
"Current variable highlight");
|
"Current variable highlight");
|
||||||
opt.registerOption(CACHED_RESULTS_SIZE_MSG,
|
opt.registerOption(CACHED_RESULTS_SIZE_MSG, SUGGESTED_CACHED_RESULTS_SIZE,
|
||||||
SUGGESTED_CACHED_RESULTS_SIZE,
|
new HelpLocation(HelpTopics.DECOMPILER, "GeneralCacheSize"), CACHE_RESULTS_DESCRIPTION);
|
||||||
new HelpLocation(HelpTopics.DECOMPILER, "GeneralCacheSize"),
|
|
||||||
CACHE_RESULTS_DESCRIPTION);
|
|
||||||
grabFromToolAndProgram(ownerPlugin, opt, program);
|
grabFromToolAndProgram(ownerPlugin, opt, program);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -751,32 +714,76 @@ public class DecompileOptions {
|
||||||
// Must set language early so that the object is in place before other option changes
|
// Must set language early so that the object is in place before other option changes
|
||||||
appendOption(buf, "setlanguage", displayLanguage.toString(), "", "");
|
appendOption(buf, "setlanguage", displayLanguage.toString(), "", "");
|
||||||
|
|
||||||
|
if (ignoreunimpl != IGNOREUNIMPL_OPTIONDEFAULT) {
|
||||||
appendOption(buf, "ignoreunimplemented", ignoreunimpl ? "on" : "off", "", "");
|
appendOption(buf, "ignoreunimplemented", ignoreunimpl ? "on" : "off", "", "");
|
||||||
|
}
|
||||||
|
if (inferconstptr != INFERCONSTPTR_OPTIONDEFAULT) {
|
||||||
appendOption(buf, "inferconstptr", inferconstptr ? "on" : "off", "", "");
|
appendOption(buf, "inferconstptr", inferconstptr ? "on" : "off", "", "");
|
||||||
|
}
|
||||||
|
if (analyzeForLoops != ANALYZEFORLOOPS_OPTIONDEFAULT) {
|
||||||
appendOption(buf, "analyzeforloops", analyzeForLoops ? "on" : "off", "", "");
|
appendOption(buf, "analyzeforloops", analyzeForLoops ? "on" : "off", "", "");
|
||||||
|
}
|
||||||
|
if (nullToken != NULLTOKEN_OPTIONDEFAULT) {
|
||||||
appendOption(buf, "nullprinting", nullToken ? "on" : "off", "", "");
|
appendOption(buf, "nullprinting", nullToken ? "on" : "off", "", "");
|
||||||
|
}
|
||||||
|
if (inplaceTokens != INPLACEOP_OPTIONDEFAULT) {
|
||||||
appendOption(buf, "inplaceops", inplaceTokens ? "on" : "off", "", "");
|
appendOption(buf, "inplaceops", inplaceTokens ? "on" : "off", "", "");
|
||||||
|
}
|
||||||
|
if (aliasBlock != ALIASBLOCK_OPTIONDEFAULT) {
|
||||||
appendOption(buf, "aliasblock", aliasBlock.getOptionString(), "", "");
|
appendOption(buf, "aliasblock", aliasBlock.getOptionString(), "", "");
|
||||||
|
}
|
||||||
|
if (conventionPrint != CONVENTION_OPTIONDEFAULT) {
|
||||||
appendOption(buf, "conventionprinting", conventionPrint ? "on" : "off", "", "");
|
appendOption(buf, "conventionprinting", conventionPrint ? "on" : "off", "", "");
|
||||||
|
}
|
||||||
|
if (noCastPrint != NOCAST_OPTIONDEFAULT) {
|
||||||
appendOption(buf, "nocastprinting", noCastPrint ? "on" : "off", "", "");
|
appendOption(buf, "nocastprinting", noCastPrint ? "on" : "off", "", "");
|
||||||
|
}
|
||||||
|
if (maxwidth != MAXWIDTH_OPTIONDEFAULT) {
|
||||||
appendOption(buf, "maxlinewidth", Integer.toString(maxwidth), "", "");
|
appendOption(buf, "maxlinewidth", Integer.toString(maxwidth), "", "");
|
||||||
|
}
|
||||||
|
if (indentwidth != INDENTWIDTH_OPTIONDEFAULT) {
|
||||||
appendOption(buf, "indentincrement", Integer.toString(indentwidth), "", "");
|
appendOption(buf, "indentincrement", Integer.toString(indentwidth), "", "");
|
||||||
|
}
|
||||||
|
if (commentindent != COMMENTINDENT_OPTIONDEFAULT) {
|
||||||
appendOption(buf, "commentindent", Integer.toString(commentindent), "", "");
|
appendOption(buf, "commentindent", Integer.toString(commentindent), "", "");
|
||||||
|
}
|
||||||
|
if (commentStyle != COMMENTSTYLE_OPTIONDEFAULT) {
|
||||||
String curstyle = CommentStyleEnum.CPPStyle.equals(commentStyle) ? "cplusplus" : "c";
|
String curstyle = CommentStyleEnum.CPPStyle.equals(commentStyle) ? "cplusplus" : "c";
|
||||||
appendOption(buf, "commentstyle", curstyle, "", "");
|
appendOption(buf, "commentstyle", curstyle, "", "");
|
||||||
appendOption(buf, "commentinstruction", "header", commentPLATEInclude ? "on" : "off", "");
|
}
|
||||||
|
if (commentPLATEInclude != COMMENTPLATE_OPTIONDEFAULT) {
|
||||||
|
appendOption(buf, "commentinstruction", "header", commentPLATEInclude ? "on" : "off",
|
||||||
|
"");
|
||||||
|
}
|
||||||
|
if (commentPREInclude != COMMENTPRE_OPTIONDEFAULT) {
|
||||||
appendOption(buf, "commentinstruction", "user2", commentPREInclude ? "on" : "off", "");
|
appendOption(buf, "commentinstruction", "user2", commentPREInclude ? "on" : "off", "");
|
||||||
|
}
|
||||||
|
if (commentEOLInclude != COMMENTEOL_OPTIONDEFAULT) {
|
||||||
appendOption(buf, "commentinstruction", "user1", commentEOLInclude ? "on" : "off", "");
|
appendOption(buf, "commentinstruction", "user1", commentEOLInclude ? "on" : "off", "");
|
||||||
|
}
|
||||||
|
if (commentPOSTInclude != COMMENTPOST_OPTIONDEFAULT) {
|
||||||
appendOption(buf, "commentinstruction", "user3", commentPOSTInclude ? "on" : "off", "");
|
appendOption(buf, "commentinstruction", "user3", commentPOSTInclude ? "on" : "off", "");
|
||||||
appendOption(buf, "commentinstruction", "warning", commentWARNInclude ? "on" : "off", "");
|
}
|
||||||
|
if (commentWARNInclude != COMMENTWARN_OPTIONDEFAULT) {
|
||||||
|
appendOption(buf, "commentinstruction", "warning", commentWARNInclude ? "on" : "off",
|
||||||
|
"");
|
||||||
|
}
|
||||||
|
if (commentHeadInclude != COMMENTHEAD_OPTIONDEFAULT) {
|
||||||
appendOption(buf, "commentheader", "header", commentHeadInclude ? "on" : "off", "");
|
appendOption(buf, "commentheader", "header", commentHeadInclude ? "on" : "off", "");
|
||||||
appendOption(buf, "commentheader", "warningheader", commentWARNInclude ? "on" : "off", "");
|
}
|
||||||
|
if (commentWARNInclude != COMMENTWARN_OPTIONDEFAULT) {
|
||||||
|
appendOption(buf, "commentheader", "warningheader", commentWARNInclude ? "on" : "off",
|
||||||
|
"");
|
||||||
|
}
|
||||||
|
if (namespaceStrategy != NAMESPACE_OPTIONDEFAULT) {
|
||||||
appendOption(buf, "namespacestrategy", namespaceStrategy.getOptionString(), "", "");
|
appendOption(buf, "namespacestrategy", namespaceStrategy.getOptionString(), "", "");
|
||||||
|
}
|
||||||
|
if (integerFormat != INTEGERFORMAT_OPTIONDEFAULT) {
|
||||||
appendOption(buf, "integerformat", integerFormat.getOptionString(), "", "");
|
appendOption(buf, "integerformat", integerFormat.getOptionString(), "", "");
|
||||||
|
}
|
||||||
|
if (maxIntructionsPer != SUGGESTED_MAX_INSTRUCTIONS) {
|
||||||
|
appendOption(buf, "maxinstruction", Integer.toString(maxIntructionsPer), "", "");
|
||||||
|
}
|
||||||
appendOption(buf, "protoeval", protoEvalModel, "", "");
|
appendOption(buf, "protoeval", protoEvalModel, "", "");
|
||||||
buf.append("</optionslist>\n");
|
buf.append("</optionslist>\n");
|
||||||
return buf.toString();
|
return buf.toString();
|
||||||
|
@ -958,6 +965,14 @@ public class DecompileOptions {
|
||||||
payloadLimitMBytes = mbytes;
|
payloadLimitMBytes = mbytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getMaxInstructions() {
|
||||||
|
return maxIntructionsPer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxInstructions(int num) {
|
||||||
|
maxIntructionsPer = num;
|
||||||
|
}
|
||||||
|
|
||||||
public CommentStyleEnum getCommentStyle() {
|
public CommentStyleEnum getCommentStyle() {
|
||||||
return commentStyle;
|
return commentStyle;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,13 +21,14 @@ import ghidra.app.plugin.assembler.sleigh.parse.AssemblyParseResult;
|
||||||
import ghidra.app.plugin.assembler.sleigh.sem.*;
|
import ghidra.app.plugin.assembler.sleigh.sem.*;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.address.AddressOverflowException;
|
import ghidra.program.model.address.AddressOverflowException;
|
||||||
import ghidra.program.model.lang.InstructionBlock;
|
|
||||||
import ghidra.program.model.listing.Instruction;
|
import ghidra.program.model.listing.Instruction;
|
||||||
|
import ghidra.program.model.listing.InstructionIterator;
|
||||||
import ghidra.program.model.mem.MemoryAccessException;
|
import ghidra.program.model.mem.MemoryAccessException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The primary interface for performing assembly in Ghidra.
|
* The primary interface for performing assembly in Ghidra.
|
||||||
*
|
*
|
||||||
|
* <p>
|
||||||
* Use the {@link Assemblers} class to obtain a suitable implementation for a given program or
|
* Use the {@link Assemblers} class to obtain a suitable implementation for a given program or
|
||||||
* language.
|
* language.
|
||||||
*/
|
*/
|
||||||
|
@ -35,26 +36,30 @@ public interface Assembler {
|
||||||
/**
|
/**
|
||||||
* Assemble a sequence of instructions and place them at the given address.
|
* Assemble a sequence of instructions and place them at the given address.
|
||||||
*
|
*
|
||||||
|
* <p>
|
||||||
* This method is only valid if the assembler is bound to a program. An instance may optionally
|
* This method is only valid if the assembler is bound to a program. An instance may optionally
|
||||||
* implement this method without a program binding. In that case, the returned instruction
|
* implement this method without a program binding. In that case, the returned iterator will
|
||||||
* block will refer to pseudo instructions.
|
* refer to pseudo instructions.
|
||||||
*
|
*
|
||||||
|
* <p>
|
||||||
* NOTE: There must be an active transaction on the bound program for this method to succeed.
|
* NOTE: There must be an active transaction on the bound program for this method to succeed.
|
||||||
*
|
*
|
||||||
* @param at the location where the resulting instructions should be placed
|
* @param at the location where the resulting instructions should be placed
|
||||||
* @param listing a new-line separated or array sequence of instructions
|
* @param listing a new-line separated or array sequence of instructions
|
||||||
* @return the block of resulting instructions
|
* @return an iterator over the resulting instructions
|
||||||
* @throws AssemblySyntaxException a textual instruction is non well-formed
|
* @throws AssemblySyntaxException a textual instruction is non well-formed
|
||||||
* @throws AssemblySemanticException a well-formed instruction cannot be assembled
|
* @throws AssemblySemanticException a well-formed instruction cannot be assembled
|
||||||
* @throws MemoryAccessException there is an issue writing the result to program memory
|
* @throws MemoryAccessException there is an issue writing the result to program memory
|
||||||
* @throws AddressOverflowException the resulting block is beyond the valid address range
|
* @throws AddressOverflowException the resulting block is beyond the valid address range
|
||||||
*/
|
*/
|
||||||
public InstructionBlock assemble(Address at, String... listing) throws AssemblySyntaxException,
|
public InstructionIterator assemble(Address at, String... listing)
|
||||||
|
throws AssemblySyntaxException,
|
||||||
AssemblySemanticException, MemoryAccessException, AddressOverflowException;
|
AssemblySemanticException, MemoryAccessException, AddressOverflowException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Assemble a line instruction at the given address.
|
* Assemble a line instruction at the given address.
|
||||||
*
|
*
|
||||||
|
* <p>
|
||||||
* This method is valid with or without a bound program. Even if bound, the program is not
|
* This method is valid with or without a bound program. Even if bound, the program is not
|
||||||
* modified; however, the appropriate context information is taken from the bound program.
|
* modified; however, the appropriate context information is taken from the bound program.
|
||||||
* Without a program, the language's default context is taken at the given location.
|
* Without a program, the language's default context is taken at the given location.
|
||||||
|
@ -71,6 +76,7 @@ public interface Assembler {
|
||||||
/**
|
/**
|
||||||
* Assemble a line instruction at the given address, assuming the given context.
|
* Assemble a line instruction at the given address, assuming the given context.
|
||||||
*
|
*
|
||||||
|
* <p>
|
||||||
* This method works like {@link #assembleLine(Address, String)} except that it allows you to
|
* This method works like {@link #assembleLine(Address, String)} except that it allows you to
|
||||||
* override the assumed context at that location.
|
* override the assumed context at that location.
|
||||||
*
|
*
|
||||||
|
@ -87,15 +93,18 @@ public interface Assembler {
|
||||||
/**
|
/**
|
||||||
* Parse a line instruction.
|
* Parse a line instruction.
|
||||||
*
|
*
|
||||||
|
* <p>
|
||||||
* Generally, you should just use {@link #assembleLine(Address, String)}, but if you'd like
|
* Generally, you should just use {@link #assembleLine(Address, String)}, but if you'd like
|
||||||
* access to the parse trees outside of an {@link AssemblySelector}, then this may be an
|
* access to the parse trees outside of an {@link AssemblySelector}, then this may be an
|
||||||
* acceptable option. Most notably, this is an excellent way to obtain suggestions for
|
* acceptable option. Most notably, this is an excellent way to obtain suggestions for
|
||||||
* auto-completion.
|
* auto-completion.
|
||||||
*
|
*
|
||||||
|
* <p>
|
||||||
* Each item in the returned collection is either a complete parse tree, or a syntax error
|
* Each item in the returned collection is either a complete parse tree, or a syntax error
|
||||||
* Because all parse paths are attempted, it's possible to get many mixed results. For example,
|
* Because all parse paths are attempted, it's possible to get many mixed results. For example,
|
||||||
* The input line may be a valid instruction; however, there may be suggestions to continue the
|
* The input line may be a valid instruction; however, there may be suggestions to continue the
|
||||||
* line toward another valid instruction.
|
* line toward another valid instruction.
|
||||||
|
*
|
||||||
* @param line the line (or partial line) to parse
|
* @param line the line (or partial line) to parse
|
||||||
* @return the results of parsing
|
* @return the results of parsing
|
||||||
*/
|
*/
|
||||||
|
@ -104,12 +113,15 @@ public interface Assembler {
|
||||||
/**
|
/**
|
||||||
* Resolve a given parse tree at the given address, assuming the given context
|
* Resolve a given parse tree at the given address, assuming the given context
|
||||||
*
|
*
|
||||||
|
* <p>
|
||||||
* Each item in the returned collection is either a completely resolved instruction, or a
|
* Each item in the returned collection is either a completely resolved instruction, or a
|
||||||
* semantic error. Because all resolutions are attempted, it's possible to get many mixed
|
* semantic error. Because all resolutions are attempted, it's possible to get many mixed
|
||||||
* results.
|
* results.
|
||||||
*
|
*
|
||||||
* NOTE: The resolved instructions are given as masks and values. Where the mask does not
|
* <p>
|
||||||
* cover, you can choose any value.
|
* NOTE: The resolved instructions are given as masks and values. Where the mask does not cover,
|
||||||
|
* you can choose any value.
|
||||||
|
*
|
||||||
* @param parse a parse result giving a valid tree
|
* @param parse a parse result giving a valid tree
|
||||||
* @param at the location of the start of the instruction
|
* @param at the location of the start of the instruction
|
||||||
* @param ctx the context register value at the start of the instruction
|
* @param ctx the context register value at the start of the instruction
|
||||||
|
@ -121,12 +133,15 @@ public interface Assembler {
|
||||||
/**
|
/**
|
||||||
* Resolve a given parse tree at the given address.
|
* Resolve a given parse tree at the given address.
|
||||||
*
|
*
|
||||||
|
* <p>
|
||||||
* Each item in the returned collection is either a completely resolved instruction, or a
|
* Each item in the returned collection is either a completely resolved instruction, or a
|
||||||
* semantic error. Because all resolutions are attempted, it's possible to get many mixed
|
* semantic error. Because all resolutions are attempted, it's possible to get many mixed
|
||||||
* results.
|
* results.
|
||||||
*
|
*
|
||||||
* NOTE: The resolved instructions are given as masks and values. Where the mask does not
|
* <p>
|
||||||
* cover, you can choose any value.
|
* NOTE: The resolved instructions are given as masks and values. Where the mask does not cover,
|
||||||
|
* you can choose any value.
|
||||||
|
*
|
||||||
* @param parse a parse result giving a valid tree
|
* @param parse a parse result giving a valid tree
|
||||||
* @param at the location of the start of the instruction
|
* @param at the location of the start of the instruction
|
||||||
* @return the results of semantic resolution
|
* @return the results of semantic resolution
|
||||||
|
@ -136,8 +151,10 @@ public interface Assembler {
|
||||||
/**
|
/**
|
||||||
* Assemble a line instruction at the given address.
|
* Assemble a line instruction at the given address.
|
||||||
*
|
*
|
||||||
|
* <p>
|
||||||
* This method works like {@link #resolveLine(Address, String, AssemblyPatternBlock)}, except
|
* This method works like {@link #resolveLine(Address, String, AssemblyPatternBlock)}, except
|
||||||
* that it derives the context using {@link #getContextAt(Address)}.
|
* that it derives the context using {@link #getContextAt(Address)}.
|
||||||
|
*
|
||||||
* @param at the location of the start of the instruction
|
* @param at the location of the start of the instruction
|
||||||
* @param line the textual assembly code
|
* @param line the textual assembly code
|
||||||
* @return the collection of semantic resolution results
|
* @return the collection of semantic resolution results
|
||||||
|
@ -149,9 +166,11 @@ public interface Assembler {
|
||||||
/**
|
/**
|
||||||
* Assemble a line instruction at the given address, assuming the given context.
|
* Assemble a line instruction at the given address, assuming the given context.
|
||||||
*
|
*
|
||||||
|
* <p>
|
||||||
* This method works like {@link #assembleLine(Address, String, AssemblyPatternBlock)}, except
|
* This method works like {@link #assembleLine(Address, String, AssemblyPatternBlock)}, except
|
||||||
* that it returns all possible resolutions for the parse trees that pass the
|
* that it returns all possible resolutions for the parse trees that pass the
|
||||||
* {@link AssemblySelector}.
|
* {@link AssemblySelector}.
|
||||||
|
*
|
||||||
* @param at the location of the start of the instruction
|
* @param at the location of the start of the instruction
|
||||||
* @param line the textual assembly code
|
* @param line the textual assembly code
|
||||||
* @param ctx the context register value at the start of the instruction
|
* @param ctx the context register value at the start of the instruction
|
||||||
|
@ -164,8 +183,10 @@ public interface Assembler {
|
||||||
/**
|
/**
|
||||||
* Place a resolved (and fully-masked) instruction into the bound program.
|
* Place a resolved (and fully-masked) instruction into the bound program.
|
||||||
*
|
*
|
||||||
* This method is not valid without a program binding. Also, this method must be called during
|
* <p>
|
||||||
* a program database transaction.
|
* This method is not valid without a program binding. Also, this method must be called during a
|
||||||
|
* program database transaction.
|
||||||
|
*
|
||||||
* @param res the resolved and fully-masked instruction
|
* @param res the resolved and fully-masked instruction
|
||||||
* @param at the location of the start of the instruction
|
* @param at the location of the start of the instruction
|
||||||
* @return the new {@link Instruction} code unit
|
* @return the new {@link Instruction} code unit
|
||||||
|
@ -175,22 +196,27 @@ public interface Assembler {
|
||||||
throws MemoryAccessException;
|
throws MemoryAccessException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Place an instruction into the bound program.
|
* Place instruction bytes into the bound program.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This method is not valid without a program binding. Also, this method must be called during a
|
||||||
|
* program database transaction.
|
||||||
*
|
*
|
||||||
* This method is not valid without a program binding. Also, this method must be called during
|
|
||||||
* a program database transaction.
|
|
||||||
* @param insbytes the instruction data
|
* @param insbytes the instruction data
|
||||||
* @param at the location of the start of the instruction
|
* @param at the location of the start of the instruction
|
||||||
* @return the new {@link Instruction} code unit
|
* @return an iterator over the disassembled instructions
|
||||||
* @throws MemoryAccessException there is an issue writing the result to program memory
|
* @throws MemoryAccessException there is an issue writing the result to program memory
|
||||||
*/
|
*/
|
||||||
public Instruction patchProgram(byte[] insbytes, Address at) throws MemoryAccessException;
|
public InstructionIterator patchProgram(byte[] insbytes, Address at)
|
||||||
|
throws MemoryAccessException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the context at a given address
|
* Get the context at a given address
|
||||||
*
|
*
|
||||||
|
* <p>
|
||||||
* If there is a program binding, this will extract the actual context at the given address.
|
* If there is a program binding, this will extract the actual context at the given address.
|
||||||
* Otherwise, it will obtain the default context at the given address for the language.
|
* Otherwise, it will obtain the default context at the given address for the language.
|
||||||
|
*
|
||||||
* @param addr the address
|
* @param addr the address
|
||||||
* @return the context
|
* @return the context
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -28,16 +28,15 @@ import ghidra.program.model.listing.Program;
|
||||||
/**
|
/**
|
||||||
* The primary class for obtaining an {@link Assembler} for a Ghidra-supported language.
|
* The primary class for obtaining an {@link Assembler} for a Ghidra-supported language.
|
||||||
*
|
*
|
||||||
|
* <p>
|
||||||
* The general flow is: First, obtain an assembler for a language or program. Second, call its
|
* The general flow is: First, obtain an assembler for a language or program. Second, call its
|
||||||
* {@link Assembler#assemble(Address, String...)} and related methods to perform assembly. More
|
* {@link Assembler#assemble(Address, String...)} and related methods to perform assembly. More
|
||||||
* advanced uses pass a {@link AssemblySelector} to control certain aspects of assembly instruction
|
* advanced uses pass a {@link AssemblySelector} to control certain aspects of assembly instruction
|
||||||
* selection, and to obtain advanced diagnostics, like detailed errors and code completion.
|
* selection, and to obtain advanced diagnostics, like detailed errors and code completion.
|
||||||
*
|
*
|
||||||
* <pre>
|
* <pre>
|
||||||
* {@code
|
|
||||||
* Assembler asm = Assemblers.getAssembler(currentProgram);
|
* Assembler asm = Assemblers.getAssembler(currentProgram);
|
||||||
* asm.assemble(currentAddress, "ADD ...");
|
* asm.assemble(currentAddress, "ADD ...");
|
||||||
* }
|
|
||||||
* </pre>
|
* </pre>
|
||||||
*/
|
*/
|
||||||
public final class Assemblers {
|
public final class Assemblers {
|
||||||
|
@ -45,6 +44,7 @@ public final class Assemblers {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a builder for the given language, possibly using a cached one.
|
* Get a builder for the given language, possibly using a cached one.
|
||||||
|
*
|
||||||
* @param lang the language
|
* @param lang the language
|
||||||
* @return the builder for that language, if successful
|
* @return the builder for that language, if successful
|
||||||
*/
|
*/
|
||||||
|
@ -64,10 +64,11 @@ public final class Assemblers {
|
||||||
/**
|
/**
|
||||||
* Get an assembler for the given program.
|
* Get an assembler for the given program.
|
||||||
*
|
*
|
||||||
* Provides an assembler suitable for the program's language, and bound to the program. Calls
|
* <p>
|
||||||
* to its Assembler#assemble() function will cause modifications to the bound program. If this
|
* Provides an assembler suitable for the program's language, and bound to the program. Calls to
|
||||||
* is the first time an assembler for the program's language has been requested, this function
|
* its Assembler#assemble() function will cause modifications to the bound program. If this is
|
||||||
* may take some time to build the assembler.
|
* the first time an assembler for the program's language has been requested, this function may
|
||||||
|
* take some time to build the assembler.
|
||||||
*
|
*
|
||||||
* @param selector a method to select a single result from many
|
* @param selector a method to select a single result from many
|
||||||
* @param program the program for which an assembler is requested
|
* @param program the program for which an assembler is requested
|
||||||
|
@ -81,6 +82,7 @@ public final class Assemblers {
|
||||||
/**
|
/**
|
||||||
* Get an assembler for the given language.
|
* Get an assembler for the given language.
|
||||||
*
|
*
|
||||||
|
* <p>
|
||||||
* Provides a suitable assembler for the given language. Only calls to its
|
* Provides a suitable assembler for the given language. Only calls to its
|
||||||
* Assembler#assembleLine() method are valid. If this is the first time a language has been
|
* Assembler#assembleLine() method are valid. If this is the first time a language has been
|
||||||
* requested, this function may take some time to build the assembler. Otherwise, it returns a
|
* requested, this function may take some time to build the assembler. Otherwise, it returns a
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.plugin.assembler.sleigh;
|
package ghidra.app.plugin.assembler.sleigh;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import ghidra.app.plugin.assembler.*;
|
import ghidra.app.plugin.assembler.*;
|
||||||
|
@ -25,7 +27,8 @@ import ghidra.app.plugin.processors.sleigh.SleighLanguage;
|
||||||
import ghidra.program.disassemble.Disassembler;
|
import ghidra.program.disassemble.Disassembler;
|
||||||
import ghidra.program.disassemble.DisassemblerMessageListener;
|
import ghidra.program.disassemble.DisassemblerMessageListener;
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.lang.*;
|
import ghidra.program.model.lang.Register;
|
||||||
|
import ghidra.program.model.lang.RegisterValue;
|
||||||
import ghidra.program.model.listing.*;
|
import ghidra.program.model.listing.*;
|
||||||
import ghidra.program.model.mem.Memory;
|
import ghidra.program.model.mem.Memory;
|
||||||
import ghidra.program.model.mem.MemoryAccessException;
|
import ghidra.program.model.mem.MemoryAccessException;
|
||||||
|
@ -98,22 +101,25 @@ public class SleighAssembler implements Assembler {
|
||||||
if (!res.getInstruction().isFullMask()) {
|
if (!res.getInstruction().isFullMask()) {
|
||||||
throw new AssemblySelectionError("Selected instruction must have a full mask.");
|
throw new AssemblySelectionError("Selected instruction must have a full mask.");
|
||||||
}
|
}
|
||||||
return patchProgram(res.getInstruction().getVals(), at);
|
return patchProgram(res.getInstruction().getVals(), at).next();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Instruction patchProgram(byte[] insbytes, Address at) throws MemoryAccessException {
|
public InstructionIterator patchProgram(byte[] insbytes, Address at)
|
||||||
listing.clearCodeUnits(at, at.add(insbytes.length - 1), false);
|
throws MemoryAccessException {
|
||||||
|
Address end = at.add(insbytes.length - 1);
|
||||||
|
listing.clearCodeUnits(at, end, false);
|
||||||
memory.setBytes(at, insbytes);
|
memory.setBytes(at, insbytes);
|
||||||
dis.disassemble(at, new AddressSet(at));
|
dis.disassemble(at, new AddressSet(at));
|
||||||
return listing.getInstructionAt(at);
|
return listing.getInstructions(new AddressSet(at, end), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public InstructionBlock assemble(Address at, String... assembly) throws AssemblySyntaxException,
|
public InstructionIterator assemble(Address at, String... assembly)
|
||||||
AssemblySemanticException, MemoryAccessException, AddressOverflowException {
|
throws AssemblySyntaxException, AssemblySemanticException, MemoryAccessException,
|
||||||
InstructionBlock block = new InstructionBlock(at);
|
AddressOverflowException {
|
||||||
|
Address start = at;
|
||||||
|
ByteArrayOutputStream buf = new ByteArrayOutputStream();
|
||||||
for (String part : assembly) {
|
for (String part : assembly) {
|
||||||
for (String line : part.split("\n")) {
|
for (String line : part.split("\n")) {
|
||||||
RegisterValue rv = program.getProgramContext().getDisassemblyContext(at);
|
RegisterValue rv = program.getProgramContext().getDisassemblyContext(at);
|
||||||
|
@ -124,13 +130,16 @@ public class SleighAssembler implements Assembler {
|
||||||
if (insbytes == null) {
|
if (insbytes == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
Instruction ins = patchProgram(insbytes, at);
|
buf.write(insbytes);
|
||||||
block.addInstruction(ins);
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
throw new AssertionError(e);
|
||||||
|
}
|
||||||
at = at.addNoWrap(insbytes.length);
|
at = at.addNoWrap(insbytes.length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return block;
|
return patchProgram(buf.toByteArray(), start);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -221,6 +230,7 @@ public class SleighAssembler implements Assembler {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A convenience to obtain a map of program labels strings to long values
|
* A convenience to obtain a map of program labels strings to long values
|
||||||
|
*
|
||||||
* @return the map
|
* @return the map
|
||||||
*
|
*
|
||||||
* {@literal TODO Use a Map<String, Address> instead so that, if possible, symbol values can be checked}
|
* {@literal TODO Use a Map<String, Address> instead so that, if possible, symbol values can be checked}
|
||||||
|
|
|
@ -24,12 +24,10 @@ import ghidra.program.model.listing.Program;
|
||||||
* This is meant to be used as an idiom in a try-with-resources block:
|
* This is meant to be used as an idiom in a try-with-resources block:
|
||||||
*
|
*
|
||||||
* <pre>
|
* <pre>
|
||||||
* {@code
|
|
||||||
* try (ProgramTransaction t = ProgramTransaction.open(program, "Demo")) {
|
* try (ProgramTransaction t = ProgramTransaction.open(program, "Demo")) {
|
||||||
* program.getMemory().....
|
* program.getMemory().....
|
||||||
* t.commit();
|
* t.commit();
|
||||||
* }
|
* }
|
||||||
* }
|
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
|
|
|
@ -588,8 +588,10 @@ public class PcodeDataTypeManager {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
int sz = type.getLength();
|
int sz = type.getLength();
|
||||||
|
boolean isVarLength = false;
|
||||||
if (sz <= 0) {
|
if (sz <= 0) {
|
||||||
sz = size;
|
sz = size;
|
||||||
|
isVarLength = true;
|
||||||
}
|
}
|
||||||
appendNameIdAttributes(resBuf, origType);
|
appendNameIdAttributes(resBuf, origType);
|
||||||
if (sz < 16) {
|
if (sz < 16) {
|
||||||
|
@ -601,6 +603,9 @@ public class PcodeDataTypeManager {
|
||||||
// Build an "opaque" structure with no fields
|
// Build an "opaque" structure with no fields
|
||||||
SpecXmlUtils.encodeStringAttribute(resBuf, "metatype", "struct");
|
SpecXmlUtils.encodeStringAttribute(resBuf, "metatype", "struct");
|
||||||
SpecXmlUtils.encodeSignedIntegerAttribute(resBuf, "size", sz);
|
SpecXmlUtils.encodeSignedIntegerAttribute(resBuf, "size", sz);
|
||||||
|
if (isVarLength) {
|
||||||
|
SpecXmlUtils.encodeBooleanAttribute(resBuf, "varlength", isVarLength);
|
||||||
|
}
|
||||||
resBuf.append('>');
|
resBuf.append('>');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,36 +15,86 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.plugin.assembler.sleigh;
|
package ghidra.app.plugin.assembler.sleigh;
|
||||||
|
|
||||||
import org.junit.Before;
|
import static org.junit.Assert.assertEquals;
|
||||||
import org.junit.Test;
|
import static org.junit.Assert.assertNotEquals;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.junit.*;
|
||||||
|
|
||||||
import generic.test.AbstractGenericTest;
|
import generic.test.AbstractGenericTest;
|
||||||
import ghidra.app.plugin.assembler.*;
|
import ghidra.app.plugin.assembler.*;
|
||||||
import ghidra.app.plugin.processors.sleigh.SleighLanguageProvider;
|
import ghidra.app.plugin.processors.sleigh.SleighLanguageProvider;
|
||||||
|
import ghidra.program.database.ProgramDB;
|
||||||
|
import ghidra.program.database.util.ProgramTransaction;
|
||||||
|
import ghidra.program.model.address.Address;
|
||||||
|
import ghidra.program.model.address.AddressOverflowException;
|
||||||
import ghidra.program.model.lang.Language;
|
import ghidra.program.model.lang.Language;
|
||||||
import ghidra.program.model.lang.LanguageID;
|
import ghidra.program.model.lang.LanguageID;
|
||||||
|
import ghidra.program.model.listing.*;
|
||||||
|
import ghidra.util.exception.CancelledException;
|
||||||
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
public class PublicAPITest extends AbstractGenericTest {
|
public class PublicAPITest extends AbstractGenericTest {
|
||||||
private Language x86;
|
Language x86;
|
||||||
|
Language toy;
|
||||||
|
|
||||||
|
Program program;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
SleighLanguageProvider provider = new SleighLanguageProvider();
|
SleighLanguageProvider provider = new SleighLanguageProvider();
|
||||||
x86 = provider.getLanguage(new LanguageID("x86:LE:64:default"));
|
x86 = provider.getLanguage(new LanguageID("x86:LE:64:default"));
|
||||||
|
toy = provider.getLanguage(new LanguageID("Toy:BE:64:default"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void tearDown() throws Exception {
|
||||||
|
if (program != null) {
|
||||||
|
program.release(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testADD0() throws AssemblySyntaxException, AssemblySemanticException {
|
public void testADD0() throws AssemblySyntaxException, AssemblySemanticException {
|
||||||
|
// Mostly just test that it doesn't crash
|
||||||
Assembler asm = Assemblers.getAssembler(x86);
|
Assembler asm = Assemblers.getAssembler(x86);
|
||||||
byte[] b =
|
byte[] b =
|
||||||
asm.assembleLine(x86.getDefaultSpace().getAddress(0x40000000), "ADD byte ptr [RBX],BL");
|
asm.assembleLine(x86.getDefaultSpace().getAddress(0x40000000), "ADD byte ptr [RBX],BL");
|
||||||
printArray(b);
|
assertNotEquals(0, b.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void printArray(byte[] arr) {
|
protected Address addr(long offset) {
|
||||||
for (int i = 0; i < arr.length; i++) {
|
return program.getAddressFactory().getDefaultAddressSpace().getAddress(offset);
|
||||||
System.out.printf("%02x", arr[i]);
|
|
||||||
}
|
}
|
||||||
System.out.println();
|
|
||||||
|
@Test
|
||||||
|
public void testAssembleWithDelaySlot() throws Exception,
|
||||||
|
AddressOverflowException, CancelledException {
|
||||||
|
program = new ProgramDB("test", toy, toy.getDefaultCompilerSpec(), this);
|
||||||
|
|
||||||
|
InstructionIterator it;
|
||||||
|
try (ProgramTransaction tid = ProgramTransaction.open(program, "Test")) {
|
||||||
|
program.getMemory()
|
||||||
|
.createInitializedBlock(".text", addr(0x00400000), 0x1000, (byte) 0,
|
||||||
|
TaskMonitor.DUMMY, false);
|
||||||
|
Assembler asm = Assemblers.getAssembler(program);
|
||||||
|
|
||||||
|
it = asm.assemble(addr(0x00400000),
|
||||||
|
"brds 0x00400004",
|
||||||
|
"add r0, #6");
|
||||||
|
|
||||||
|
tid.commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Instruction> result = new ArrayList<>();
|
||||||
|
while (it.hasNext()) {
|
||||||
|
result.add(it.next());
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals(2, result.size());
|
||||||
|
assertEquals("brds", result.get(0).getMnemonicString());
|
||||||
|
assertEquals("_add", result.get(1).getMnemonicString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -349,6 +349,14 @@ cc: "M" is bits3_3=0x7 { export S_flag;
|
||||||
setResultFlags(A);
|
setResultFlags(A);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:XRA (HL) is op0_8=0xae & HL {
|
||||||
|
AC_flag = 0;
|
||||||
|
CY_flag = 0;
|
||||||
|
P_flag = 0;
|
||||||
|
A = A ^ *:1 HL;
|
||||||
|
setResultFlags(A);
|
||||||
|
}
|
||||||
|
|
||||||
:XRI imm8 is op0_8=0xee; imm8 {
|
:XRI imm8 is op0_8=0xee; imm8 {
|
||||||
AC_flag = 0;
|
AC_flag = 0;
|
||||||
CY_flag = 0;
|
CY_flag = 0;
|
||||||
|
|
|
@ -5,14 +5,15 @@ data/languages/mips.dwarf||GHIDRA||||END|
|
||||||
data/languages/mips.ldefs||GHIDRA||||END|
|
data/languages/mips.ldefs||GHIDRA||||END|
|
||||||
data/languages/mips.sinc||GHIDRA||||END|
|
data/languages/mips.sinc||GHIDRA||||END|
|
||||||
data/languages/mips16.sinc||GHIDRA||||END|
|
data/languages/mips16.sinc||GHIDRA||||END|
|
||||||
data/languages/mips32.cspec||GHIDRA||||END|
|
|
||||||
data/languages/mips32.pspec||GHIDRA||||END|
|
data/languages/mips32.pspec||GHIDRA||||END|
|
||||||
data/languages/mips32Instructions.sinc||GHIDRA||||END|
|
data/languages/mips32Instructions.sinc||GHIDRA||||END|
|
||||||
data/languages/mips32R6.pspec||GHIDRA||||END|
|
data/languages/mips32R6.pspec||GHIDRA||||END|
|
||||||
data/languages/mips32R6be.slaspec||GHIDRA||||END|
|
data/languages/mips32R6be.slaspec||GHIDRA||||END|
|
||||||
data/languages/mips32R6le.slaspec||GHIDRA||||END|
|
data/languages/mips32R6le.slaspec||GHIDRA||||END|
|
||||||
data/languages/mips32_fp64.cspec||GHIDRA||||END|
|
data/languages/mips32_fp64.cspec||GHIDRA||||END|
|
||||||
|
data/languages/mips32be.cspec||GHIDRA||||END|
|
||||||
data/languages/mips32be.slaspec||GHIDRA||||END|
|
data/languages/mips32be.slaspec||GHIDRA||||END|
|
||||||
|
data/languages/mips32le.cspec||GHIDRA||||END|
|
||||||
data/languages/mips32le.slaspec||GHIDRA||||END|
|
data/languages/mips32le.slaspec||GHIDRA||||END|
|
||||||
data/languages/mips32micro.pspec||GHIDRA||||END|
|
data/languages/mips32micro.pspec||GHIDRA||||END|
|
||||||
data/languages/mips64.cspec||GHIDRA||||END|
|
data/languages/mips64.cspec||GHIDRA||||END|
|
||||||
|
|
|
@ -10,8 +10,8 @@
|
||||||
manualindexfile="../manuals/mipsM16.idx"
|
manualindexfile="../manuals/mipsM16.idx"
|
||||||
id="MIPS:BE:32:default">
|
id="MIPS:BE:32:default">
|
||||||
<description>MIPS32 32-bit addresses, big endian, with mips16e</description>
|
<description>MIPS32 32-bit addresses, big endian, with mips16e</description>
|
||||||
<compiler name="default" spec="mips32.cspec" id="default"/>
|
<compiler name="default" spec="mips32be.cspec" id="default"/>
|
||||||
<compiler name="Visual Studio" spec="mips32.cspec" id="windows"/>
|
<compiler name="Visual Studio" spec="mips32be.cspec" id="windows"/>
|
||||||
<external_name tool="gnu" name="mips:4000"/>
|
<external_name tool="gnu" name="mips:4000"/>
|
||||||
<external_name tool="IDA-PRO" name="mipsb"/>
|
<external_name tool="IDA-PRO" name="mipsb"/>
|
||||||
<external_name tool="DWARF.register.mapping.file" name="mips.dwarf"/>
|
<external_name tool="DWARF.register.mapping.file" name="mips.dwarf"/>
|
||||||
|
@ -26,8 +26,8 @@
|
||||||
manualindexfile="../manuals/mipsM16.idx"
|
manualindexfile="../manuals/mipsM16.idx"
|
||||||
id="MIPS:LE:32:default">
|
id="MIPS:LE:32:default">
|
||||||
<description>MIPS32 32-bit addresses, little endian, with mips16e</description>
|
<description>MIPS32 32-bit addresses, little endian, with mips16e</description>
|
||||||
<compiler name="default" spec="mips32.cspec" id="default"/>
|
<compiler name="default" spec="mips32le.cspec" id="default"/>
|
||||||
<compiler name="Visual Studio" spec="mips32.cspec" id="windows"/>
|
<compiler name="Visual Studio" spec="mips32le.cspec" id="windows"/>
|
||||||
<external_name tool="gnu" name="mips:4000"/>
|
<external_name tool="gnu" name="mips:4000"/>
|
||||||
<external_name tool="IDA-PRO" name="mipsl"/>
|
<external_name tool="IDA-PRO" name="mipsl"/>
|
||||||
<external_name tool="DWARF.register.mapping.file" name="mips.dwarf"/>
|
<external_name tool="DWARF.register.mapping.file" name="mips.dwarf"/>
|
||||||
|
@ -284,7 +284,7 @@
|
||||||
manualindexfile="../manuals/mipsMic.idx"
|
manualindexfile="../manuals/mipsMic.idx"
|
||||||
id="MIPS:BE:32:micro">
|
id="MIPS:BE:32:micro">
|
||||||
<description>MIPS32 32-bit addresses, big endian, with microMIPS</description>
|
<description>MIPS32 32-bit addresses, big endian, with microMIPS</description>
|
||||||
<compiler name="default" spec="mips32.cspec" id="default"/>
|
<compiler name="default" spec="mips32be.cspec" id="default"/>
|
||||||
<external_name tool="gnu" name="mips:micromips"/>
|
<external_name tool="gnu" name="mips:micromips"/>
|
||||||
<external_name tool="IDA-PRO" name="mipsb"/>
|
<external_name tool="IDA-PRO" name="mipsb"/>
|
||||||
<external_name tool="DWARF.register.mapping.file" name="mips.dwarf"/>
|
<external_name tool="DWARF.register.mapping.file" name="mips.dwarf"/>
|
||||||
|
@ -299,8 +299,8 @@
|
||||||
manualindexfile="../manuals/mipsMic.idx"
|
manualindexfile="../manuals/mipsMic.idx"
|
||||||
id="MIPS:LE:32:micro">
|
id="MIPS:LE:32:micro">
|
||||||
<description>MIPS32 32-bit addresses, little endian, with microMIPS</description>
|
<description>MIPS32 32-bit addresses, little endian, with microMIPS</description>
|
||||||
<compiler name="default" spec="mips32.cspec" id="default"/>
|
<compiler name="default" spec="mips32le.cspec" id="default"/>
|
||||||
<compiler name="Visual Studio" spec="mips32.cspec" id="windows"/>
|
<compiler name="Visual Studio" spec="mips32le.cspec" id="windows"/>
|
||||||
<external_name tool="IDA-PRO" name="mipsl"/>
|
<external_name tool="IDA-PRO" name="mipsl"/>
|
||||||
<external_name tool="DWARF.register.mapping.file" name="mips.dwarf"/>
|
<external_name tool="DWARF.register.mapping.file" name="mips.dwarf"/>
|
||||||
</language>
|
</language>
|
||||||
|
|
90
Ghidra/Processors/MIPS/data/languages/mips32le.cspec
Normal file
90
Ghidra/Processors/MIPS/data/languages/mips32le.cspec
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<compiler_spec>
|
||||||
|
<data_organization>
|
||||||
|
<pointer_size value="4"/>
|
||||||
|
<float_size value="4" />
|
||||||
|
<double_size value="8" />
|
||||||
|
<long_double_size value="8" />
|
||||||
|
<size_alignment_map>
|
||||||
|
<entry size="1" alignment="1" />
|
||||||
|
<entry size="2" alignment="2" />
|
||||||
|
<entry size="4" alignment="4" />
|
||||||
|
<entry size="8" alignment="8" />
|
||||||
|
</size_alignment_map>
|
||||||
|
</data_organization>
|
||||||
|
|
||||||
|
<stackpointer register="sp" space="ram"/>
|
||||||
|
<funcptr align="2"/>
|
||||||
|
<spacebase name="gp" register="gp" space="ram"/>
|
||||||
|
<global>
|
||||||
|
<range space="gp"/>
|
||||||
|
<range space="ram"/>
|
||||||
|
<range space="register" first="0x2000" last="0x2fff"/>
|
||||||
|
</global>
|
||||||
|
<returnaddress>
|
||||||
|
<register name="ra"/>
|
||||||
|
</returnaddress>
|
||||||
|
<default_proto>
|
||||||
|
<prototype name="__stdcall" extrapop="0" stackshift="0">
|
||||||
|
<input>
|
||||||
|
<pentry minsize="1" maxsize="8" metatype="float">
|
||||||
|
<register name="f12_13"/>
|
||||||
|
</pentry>
|
||||||
|
<pentry minsize="1" maxsize="8" metatype="float">
|
||||||
|
<register name="f14_15"/>
|
||||||
|
</pentry>
|
||||||
|
<pentry minsize="1" maxsize="4">
|
||||||
|
<register name="a0"/>
|
||||||
|
</pentry>
|
||||||
|
<pentry minsize="1" maxsize="4">
|
||||||
|
<register name="a1"/>
|
||||||
|
</pentry>
|
||||||
|
<pentry minsize="1" maxsize="4">
|
||||||
|
<register name="a2"/>
|
||||||
|
</pentry>
|
||||||
|
<pentry minsize="1" maxsize="4">
|
||||||
|
<register name="a3"/>
|
||||||
|
</pentry>
|
||||||
|
<pentry minsize="1" maxsize="500" align="4">
|
||||||
|
<addr offset="16" space="stack"/>
|
||||||
|
</pentry>
|
||||||
|
</input>
|
||||||
|
<output>
|
||||||
|
<pentry minsize="1" maxsize="8" metatype="float">
|
||||||
|
<register name="f0_1"/>
|
||||||
|
</pentry>
|
||||||
|
<pentry minsize="1" maxsize="4">
|
||||||
|
<register name="v0"/>
|
||||||
|
</pentry>
|
||||||
|
<pentry minsize="5" maxsize="8">
|
||||||
|
<addr space="join" piece1="v1" piece2="v0"/>
|
||||||
|
</pentry>
|
||||||
|
</output>
|
||||||
|
<unaffected>
|
||||||
|
<register name="s0"/>
|
||||||
|
<register name="s1"/>
|
||||||
|
<register name="s2"/>
|
||||||
|
<register name="s3"/>
|
||||||
|
<register name="s4"/>
|
||||||
|
<register name="s5"/>
|
||||||
|
<register name="s6"/>
|
||||||
|
<register name="s7"/>
|
||||||
|
<register name="s8"/>
|
||||||
|
<register name="sp"/>
|
||||||
|
<register name="gp"/>
|
||||||
|
<register name="f20"/>
|
||||||
|
<register name="f22"/>
|
||||||
|
<register name="f24"/>
|
||||||
|
<register name="f26"/>
|
||||||
|
<register name="f28"/>
|
||||||
|
<register name="f30"/>
|
||||||
|
</unaffected>
|
||||||
|
<localrange>
|
||||||
|
<range space="stack" first="0xfff0bdc0" last="0xffffffff"/>
|
||||||
|
<range space="stack" first="0" last="15"/> <!-- This is backup storage space for register params, but we treat as locals -->
|
||||||
|
</localrange>
|
||||||
|
</prototype>
|
||||||
|
</default_proto>
|
||||||
|
|
||||||
|
</compiler_spec>
|
|
@ -86,8 +86,8 @@ define ram offset=0x36 size=2 [ RCOUNT ]; # Repeat counter
|
||||||
# define ram offset=0x38 size=2 [ DCOUNT ]; # 13 bits long DO Loop counter
|
# define ram offset=0x38 size=2 [ DCOUNT ]; # 13 bits long DO Loop counter
|
||||||
define ram offset=0x54 size=1 [ TBLPAG ]; # 7bit Data Table Page Address
|
define ram offset=0x54 size=1 [ TBLPAG ]; # 7bit Data Table Page Address
|
||||||
@else
|
@else
|
||||||
define ram offset=0x31 size=1 [ TBLPAG ]; # 8bit Data Table Page Address
|
define ram offset=0x32 size=1 [ TBLPAG ]; # 8bit Data Table Page Address
|
||||||
define ram offset=0x33 size=1 [ PSVPAG ]; # Program Memory Visibility Page Address Pointer
|
define ram offset=0x34 size=1 [ PSVPAG ]; # Program Memory Visibility Page Address Pointer
|
||||||
define ram offset=0x36 size=2 [ RCOUNT ]; # Repeat counter
|
define ram offset=0x36 size=2 [ RCOUNT ]; # Repeat counter
|
||||||
define ram offset=0x38 size=2 [ DCOUNT ]; # 13 bits long DO Loop counter
|
define ram offset=0x38 size=2 [ DCOUNT ]; # 13 bits long DO Loop counter
|
||||||
define ram offset=0x3A size=3 [ DOSTART ];
|
define ram offset=0x3A size=3 [ DOSTART ];
|
||||||
|
|
|
@ -81,6 +81,9 @@ VMARGS_WINDOWS=-Dlog4j.skipJansi=true
|
||||||
# Ghidra does not use class data sharing, so explicitly turn it off to avoid the warning.
|
# Ghidra does not use class data sharing, so explicitly turn it off to avoid the warning.
|
||||||
VMARGS=-Xshare:off
|
VMARGS=-Xshare:off
|
||||||
|
|
||||||
|
# Permit "illegal reflective accesses" to enable compatibility with some 3rd party jars
|
||||||
|
VMARGS=--illegal-access=permit
|
||||||
|
|
||||||
# Persistent cache directory used by the application. This directory will be used to store
|
# Persistent cache directory used by the application. This directory will be used to store
|
||||||
# persistent application caches for all users. The default location for Mac/Linux is the same as
|
# persistent application caches for all users. The default location for Mac/Linux is the same as
|
||||||
# specified by java.io.tmpdir property. The default location for Windows corresponds to the
|
# specified by java.io.tmpdir property. The default location for Windows corresponds to the
|
||||||
|
|
|
@ -261,7 +261,7 @@ class XmlExporter:
|
||||||
elif ch == '\'' : return "'"
|
elif ch == '\'' : return "'"
|
||||||
elif ch == '"' : return """
|
elif ch == '"' : return """
|
||||||
elif ch == '\x7F': return ''
|
elif ch == '\x7F': return ''
|
||||||
elif ord(ch) > 0x7F: return '&#x' + format((ord(ch),"x")) + ";"
|
elif ord(ch) > 0x7F: return '&#x' + format(ord(ch),"x") + ";"
|
||||||
return ch
|
return ch
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -647,7 +647,7 @@ class XmlExporter(IdaXml):
|
||||||
# tag_remove seems to be losing last character
|
# tag_remove seems to be losing last character
|
||||||
# work around is to add a space
|
# work around is to add a space
|
||||||
cmt_text = ida_lines.tag_remove(cmt + ' ')
|
cmt_text = ida_lines.tag_remove(cmt + ' ')
|
||||||
self.write_text(cmt_text)
|
self.write_text(cmt_text.decode('utf-8'))
|
||||||
self.end_element(COMMENT, False)
|
self.end_element(COMMENT, False)
|
||||||
|
|
||||||
|
|
||||||
|
@ -2395,7 +2395,7 @@ class XmlImporter(IdaXml):
|
||||||
# overlayed addresses not currently handled
|
# overlayed addresses not currently handled
|
||||||
return BADADDR
|
return BADADDR
|
||||||
elif ':' in addrstr:
|
elif ':' in addrstr:
|
||||||
[segstr, offset_str] = string.split(addrstr,':')
|
[segstr, offset_str] = str.split(addrstr,':')
|
||||||
offset = int(offset_str,16)
|
offset = int(offset_str,16)
|
||||||
if self.is_int(segstr) == True:
|
if self.is_int(segstr) == True:
|
||||||
sgmt = int(segstr,16)
|
sgmt = int(segstr,16)
|
||||||
|
@ -3111,11 +3111,11 @@ class XmlImporter(IdaXml):
|
||||||
"""
|
"""
|
||||||
regcmt = member.find(REGULAR_CMT)
|
regcmt = member.find(REGULAR_CMT)
|
||||||
if regcmt != None:
|
if regcmt != None:
|
||||||
idc.set_member_cmt(mbr, regcmt.text, False)
|
ida_struct.set_member_cmt(mbr, regcmt.text, False)
|
||||||
self.update_counter(MEMBER + ':' + REGULAR_CMT)
|
self.update_counter(MEMBER + ':' + REGULAR_CMT)
|
||||||
rptcmt = member.find(REPEATABLE_CMT)
|
rptcmt = member.find(REPEATABLE_CMT)
|
||||||
if rptcmt != None:
|
if rptcmt != None:
|
||||||
idc.set_member_cmt(mbr, rptcmt.text, True)
|
ida_struct.set_member_cmt(mbr, rptcmt.text, True)
|
||||||
self.update_counter(MEMBER + ':' + REPEATABLE_CMT)
|
self.update_counter(MEMBER + ':' + REPEATABLE_CMT)
|
||||||
|
|
||||||
|
|
||||||
|
@ -3239,7 +3239,7 @@ class XmlImporter(IdaXml):
|
||||||
idc.warning(msg)
|
idc.warning(msg)
|
||||||
return
|
return
|
||||||
elif ':' in addrstr:
|
elif ':' in addrstr:
|
||||||
[seg_str, offset_str] = string.split(addrstr,':')
|
[seg_str, offset_str] = str.split(addrstr,':')
|
||||||
offset = int(offset_str, 16)
|
offset = int(offset_str, 16)
|
||||||
if self.is_int(seg_str):
|
if self.is_int(seg_str):
|
||||||
base = int(seg_str, 16)
|
base = int(seg_str, 16)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue