Allow SLEIGH bitrange operator applied to dynamic varnodes

This commit is contained in:
caheckman 2022-01-03 17:03:29 -05:00
parent e440e3333f
commit 311a22c038
63 changed files with 1064 additions and 747 deletions

View file

@ -18,7 +18,6 @@ package ghidra.trace.util;
import java.util.List; import java.util.List;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.address.UniqueAddressFactory;
import ghidra.program.model.lang.*; import ghidra.program.model.lang.*;
import ghidra.program.model.listing.Instruction; import ghidra.program.model.listing.Instruction;
import ghidra.program.model.listing.InstructionPcodeOverride; import ghidra.program.model.listing.InstructionPcodeOverride;
@ -137,13 +136,8 @@ public interface InstructionAdapterFromPrototype extends Instruction {
@Override @Override
default RefType getOperandRefType(int opIndex) { default RefType getOperandRefType(int opIndex) {
InstructionPrototype prototype = getPrototype(); InstructionPrototype prototype = getPrototype();
Language language = prototype.getLanguage();
InstructionPcodeOverride override = new InstructionPcodeOverride(this); InstructionPcodeOverride override = new InstructionPcodeOverride(this);
// TODO: addressFactory may need to be from program/trace (so it has cSpec) return prototype.getOperandRefType(opIndex, getInstructionContext(), override);
UniqueAddressFactory uniqueFactory =
new UniqueAddressFactory(language.getAddressFactory(), language);
return prototype.getOperandRefType(opIndex, getInstructionContext(), override,
uniqueFactory);
} }
@Override @Override
@ -159,14 +153,11 @@ public interface InstructionAdapterFromPrototype extends Instruction {
@Override @Override
default PcodeOp[] getPcode(boolean includeOverrides) { default PcodeOp[] getPcode(boolean includeOverrides) {
if (!includeOverrides) { if (!includeOverrides) {
return getPrototype().getPcode(getInstructionContext(), null, null); return getPrototype().getPcode(getInstructionContext(), null);
} }
InstructionPrototype prototype = getPrototype(); InstructionPrototype prototype = getPrototype();
Language language = prototype.getLanguage();
InstructionPcodeOverride override = new InstructionPcodeOverride(this); InstructionPcodeOverride override = new InstructionPcodeOverride(this);
UniqueAddressFactory uniqueFactory = return prototype.getPcode(getInstructionContext(), override);
new UniqueAddressFactory(language.getAddressFactory(), language);
return prototype.getPcode(getInstructionContext(), override, uniqueFactory);
} }
/** /**

View file

@ -18,55 +18,28 @@ package ghidra.pcode.exec;
import java.util.*; import java.util.*;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.jdom.JDOMException;
import org.xml.sax.*;
import ghidra.app.plugin.processors.sleigh.*; import ghidra.app.plugin.processors.sleigh.*;
import ghidra.app.plugin.processors.sleigh.template.ConstructTpl; import ghidra.app.plugin.processors.sleigh.template.ConstructTpl;
import ghidra.pcodeCPort.slgh_compile.PcodeParser;
import ghidra.pcodeCPort.slghsymbol.UserOpSymbol; import ghidra.pcodeCPort.slghsymbol.UserOpSymbol;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.lang.Language; import ghidra.program.model.lang.*;
import ghidra.program.model.lang.UnknownInstructionException;
import ghidra.program.model.mem.MemoryAccessException; import ghidra.program.model.mem.MemoryAccessException;
import ghidra.program.model.pcode.PcodeOp; import ghidra.program.model.pcode.PcodeOp;
import ghidra.util.Msg;
import ghidra.xml.XmlPullParser;
import ghidra.xml.XmlPullParserFactory;
public class SleighProgramCompiler { public class SleighProgramCompiler {
private static final String EXPRESSION_SOURCE_NAME = "expression"; private static final String EXPRESSION_SOURCE_NAME = "expression";
public static PcodeParser createParser(SleighLanguage language) { public static PcodeParser createParser(SleighLanguage language) {
String translatorTag = return new PcodeParser(language, UniqueLayout.INJECT.getOffset(language));
language.buildTranslatorTag(language.getAddressFactory(), language.getUniqueBase(),
language.getSymbolTable());
try {
return new PcodeParser(translatorTag);
}
catch (JDOMException e) {
throw new AssertionError(e);
}
} }
public static ConstructTpl compileTemplate(Language language, PcodeParser parser, public static ConstructTpl compileTemplate(Language language, PcodeParser parser,
String sourceName, String text) { String sourceName, String text) {
try { ConstructTpl template =
// This is quite the conversion, no? Objects.requireNonNull(parser.compilePcode(text, EXPRESSION_SOURCE_NAME, 1));
String templateXml =
PcodeParser.stringifyTemplate(
Objects.requireNonNull(parser.compilePcode(text, EXPRESSION_SOURCE_NAME, 1)));
MyErrorHandler eh = new MyErrorHandler();
XmlPullParser xmlParser =
XmlPullParserFactory.create(templateXml, EXPRESSION_SOURCE_NAME, eh, false);
ConstructTpl template = new ConstructTpl();
template.restoreXml(xmlParser, language.getAddressFactory());
return template; return template;
} }
catch (SAXException | UnknownInstructionException e) {
throw new AssertionError(e);
}
}
public static List<PcodeOp> buildOps(Language language, ConstructTpl template) public static List<PcodeOp> buildOps(Language language, ConstructTpl template)
throws UnknownInstructionException, MemoryAccessException { throws UnknownInstructionException, MemoryAccessException {
@ -125,23 +98,4 @@ public class SleighProgramCompiler {
throw new AssertionError(e); throw new AssertionError(e);
} }
} }
static class MyErrorHandler implements ErrorHandler {
SAXParseException exc;
@Override
public void warning(SAXParseException e) throws SAXException {
Msg.warn(this, e);
}
@Override
public void error(SAXParseException e) throws SAXException {
exc = e;
}
@Override
public void fatalError(SAXParseException e) throws SAXException {
exc = e;
}
}
} }

View file

@ -13,8 +13,10 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
//Uses overriding references and the symbolic propogator to resolve system calls //Uses overriding references and the symbolic propogator to resolve system calls
//@category Analysis //@category Analysis
import java.io.*; import java.io.*;
import java.util.*; import java.util.*;
import java.util.Map.Entry; import java.util.Map.Entry;
@ -31,8 +33,8 @@ import ghidra.app.util.opinion.ElfLoader;
import ghidra.framework.Application; import ghidra.framework.Application;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.program.model.data.DataTypeManager; import ghidra.program.model.data.DataTypeManager;
import ghidra.program.model.lang.BasicCompilerSpec;
import ghidra.program.model.lang.Register; import ghidra.program.model.lang.Register;
import ghidra.program.model.lang.SpaceNames;
import ghidra.program.model.listing.*; import ghidra.program.model.listing.*;
import ghidra.program.model.mem.MemoryAccessException; import ghidra.program.model.mem.MemoryAccessException;
import ghidra.program.model.pcode.PcodeOp; import ghidra.program.model.pcode.PcodeOp;
@ -127,8 +129,9 @@ public class ResolveX86orX64LinuxSyscallsScript extends GhidraScript {
" to run this script"); " to run this script");
return; return;
} }
Address startAddr = currentProgram.getAddressFactory().getAddressSpace( Address startAddr = currentProgram.getAddressFactory()
BasicCompilerSpec.OTHER_SPACE_NAME).getAddress(0x0L); .getAddressSpace(SpaceNames.OTHER_SPACE_NAME)
.getAddress(0x0L);
AddUninitializedMemoryBlockCmd cmd = new AddUninitializedMemoryBlockCmd( AddUninitializedMemoryBlockCmd cmd = new AddUninitializedMemoryBlockCmd(
SYSCALL_SPACE_NAME, null, this.getClass().getName(), startAddr, SYSCALL_SPACE_NAME, null, this.getClass().getName(), startAddr,
SYSCALL_SPACE_LENGTH, true, true, true, false, true); SYSCALL_SPACE_LENGTH, true, true, true, false, true);
@ -188,8 +191,9 @@ public class ResolveX86orX64LinuxSyscallsScript extends GhidraScript {
callee.setNoReturn(true); callee.setNoReturn(true);
} }
} }
Reference ref = currentProgram.getReferenceManager().addMemoryReference(callSite, Reference ref = currentProgram.getReferenceManager()
callTarget, overrideType, SourceType.USER_DEFINED, Reference.MNEMONIC); .addMemoryReference(callSite, callTarget, overrideType, SourceType.USER_DEFINED,
Reference.MNEMONIC);
//overriding references must be primary to be active //overriding references must be primary to be active
currentProgram.getReferenceManager().setPrimary(ref, true); currentProgram.getReferenceManager().setPrimary(ref, true);
} }
@ -320,8 +324,10 @@ public class ResolveX86orX64LinuxSyscallsScript extends GhidraScript {
for (PcodeOp op : inst.getPcode()) { for (PcodeOp op : inst.getPcode()) {
if (op.getOpcode() == PcodeOp.CALLOTHER) { if (op.getOpcode() == PcodeOp.CALLOTHER) {
int index = (int) op.getInput(0).getOffset(); int index = (int) op.getInput(0).getOffset();
if (inst.getProgram().getLanguage().getUserDefinedOpName(index).equals( if (inst.getProgram()
SYSCALL_X64_CALLOTHER)) { .getLanguage()
.getUserDefinedOpName(index)
.equals(SYSCALL_X64_CALLOTHER)) {
retVal = true; retVal = true;
} }
} }

View file

@ -644,9 +644,9 @@ void Architecture::restoreFromSpec(DocumentStorage &store)
translate = newtrans; translate = newtrans;
modifySpaces(newtrans); // Give architecture chance to modify spaces, before copying modifySpaces(newtrans); // Give architecture chance to modify spaces, before copying
copySpaces(newtrans); copySpaces(newtrans);
insertSpace( new FspecSpace(this,translate,"fspec",numSpaces())); insertSpace( new FspecSpace(this,translate,numSpaces()));
insertSpace( new IopSpace(this,translate,"iop",numSpaces())); insertSpace( new IopSpace(this,translate,numSpaces()));
insertSpace( new JoinSpace(this,translate,"join",numSpaces())); insertSpace( new JoinSpace(this,translate,numSpaces()));
userops.initialize(this); userops.initialize(this);
if (translate->getAlignment() <= 8) if (translate->getAlignment() <= 8)
min_funcsymbol_size = translate->getAlignment(); min_funcsymbol_size = translate->getAlignment();
@ -843,7 +843,7 @@ void Architecture::addOtherSpace(void)
{ {
Scope *scope = symboltab->getGlobalScope(); Scope *scope = symboltab->getGlobalScope();
AddrSpace *otherSpace = getSpaceByName("OTHER"); AddrSpace *otherSpace = getSpaceByName(OtherSpace::NAME);
symboltab->addRange(scope,otherSpace,0,otherSpace->getHighest()); symboltab->addRange(scope,otherSpace,0,otherSpace->getHighest());
if (otherSpace->isOverlayBase()) { if (otherSpace->isOverlayBase()) {
int4 num = numSpaces(); int4 num = numSpaces();

View file

@ -1702,16 +1702,17 @@ int4 ParamActive::getNumUsed(void) const
return count; return count;
} }
const string FspecSpace::NAME = "fspec";
/// Constructor for the \b fspec space. /// Constructor for the \b fspec space.
/// There is only one such space, and it is considered /// There is only one such space, and it is considered
/// internal to the model, i.e. the Translate engine should never /// internal to the model, i.e. the Translate engine should never
/// generate addresses in this space. /// generate addresses in this space.
/// \param m is the associated address space manager /// \param m is the associated address space manager
/// \param t is the associated processor translator /// \param t is the associated processor translator
/// \param nm is the name of the space (always \b fspec)
/// \param ind is the index associated with the space /// \param ind is the index associated with the space
FspecSpace::FspecSpace(AddrSpaceManager *m,const Translate *t,const string &nm,int4 ind) FspecSpace::FspecSpace(AddrSpaceManager *m,const Translate *t,int4 ind)
: AddrSpace(m,t,IPTR_FSPEC,nm,sizeof(void *),1,ind,0,1) : AddrSpace(m,t,IPTR_FSPEC,NAME,sizeof(void *),1,ind,0,1)
{ {
clearFlags(heritaged|does_deadcode|big_endian); clearFlags(heritaged|does_deadcode|big_endian);
if (HOST_ENDIAN==1) // Endianness always set by host if (HOST_ENDIAN==1) // Endianness always set by host

View file

@ -286,12 +286,13 @@ public:
/// value of the pointer /// value of the pointer
class FspecSpace : public AddrSpace { class FspecSpace : public AddrSpace {
public: public:
FspecSpace(AddrSpaceManager *m,const Translate *t,const string &nm,int4 ind); ///< Constructor FspecSpace(AddrSpaceManager *m,const Translate *t,int4 ind); ///< Constructor
virtual void saveXmlAttributes(ostream &s,uintb offset) const; virtual void saveXmlAttributes(ostream &s,uintb offset) const;
virtual void saveXmlAttributes(ostream &s,uintb offset,int4 size) const; virtual void saveXmlAttributes(ostream &s,uintb offset,int4 size) const;
virtual void printRaw(ostream &s,uintb offset) const; virtual void printRaw(ostream &s,uintb offset) const;
virtual void saveXml(ostream &s) const; virtual void saveXml(ostream &s) const;
virtual void restoreXml(const Element *el); virtual void restoreXml(const Element *el);
static const string NAME; ///< Reserved name for the fspec space
}; };
/// \brief Basic elements of a parameter: address, data-type, properties /// \brief Basic elements of a parameter: address, data-type, properties

View file

@ -24,9 +24,7 @@
Funcdata::Funcdata(const string &nm,Scope *scope,const Address &addr,FunctionSymbol *sym,int4 sz) Funcdata::Funcdata(const string &nm,Scope *scope,const Address &addr,FunctionSymbol *sym,int4 sz)
: baseaddr(addr), : baseaddr(addr),
funcp(), funcp(),
vbank(scope->getArch(), vbank(scope->getArch()),
scope->getArch()->getUniqueSpace(),
0x10000000), // Unique space which is reused per function starts here
heritage(this), heritage(this),
covermerge(*this) covermerge(*this)

View file

@ -278,8 +278,8 @@ void InjectPayloadDynamic::inject(InjectContext &context,PcodeEmit &emit) const
emit.restoreXmlOp(*iter,glb->translate); emit.restoreXmlOp(*iter,glb->translate);
} }
PcodeInjectLibrarySleigh::PcodeInjectLibrarySleigh(Architecture *g,uintb tmpbase) PcodeInjectLibrarySleigh::PcodeInjectLibrarySleigh(Architecture *g)
: PcodeInjectLibrary(g,tmpbase) : PcodeInjectLibrary(g,g->translate->getUniqueStart(Translate::INJECT))
{ {
slgh = (const SleighBase *)g->translate; slgh = (const SleighBase *)g->translate;
contextCache.glb = g; contextCache.glb = g;

View file

@ -97,7 +97,7 @@ protected:
virtual int4 allocateInject(const string &sourceName,const string &name,int4 type); virtual int4 allocateInject(const string &sourceName,const string &name,int4 type);
virtual void registerInject(int4 injectid); virtual void registerInject(int4 injectid);
public: public:
PcodeInjectLibrarySleigh(Architecture *g,uintb tmpbase); PcodeInjectLibrarySleigh(Architecture *g);
virtual void restoreDebug(const Element *el); virtual void restoreDebug(const Element *el);
virtual int4 manualCallFixup(const string &name,const string &snippetstring); virtual int4 manualCallFixup(const string &name,const string &snippetstring);
virtual int4 manualCallOtherFixup(const string &name,const string &outname,const vector<string> &inname, virtual int4 manualCallOtherFixup(const string &name,const string &outname,const vector<string> &inname,

View file

@ -16,16 +16,17 @@
#include "op.hh" #include "op.hh"
#include "funcdata.hh" #include "funcdata.hh"
const string IopSpace::NAME = "iop";
/// Constructor for the \b iop space. /// Constructor for the \b iop space.
/// There is only one such space, and it is considered internal /// There is only one such space, and it is considered internal
/// to the model, i.e. the Translate engine should never generate /// to the model, i.e. the Translate engine should never generate
/// addresses in this space. /// addresses in this space.
/// \param m is the associated address space manager /// \param m is the associated address space manager
/// \param t is the associated processor translator /// \param t is the associated processor translator
/// \param nm is the name of the space (always \b iop)
/// \param ind is the associated index /// \param ind is the associated index
IopSpace::IopSpace(AddrSpaceManager *m,const Translate *t,const string &nm,int4 ind) IopSpace::IopSpace(AddrSpaceManager *m,const Translate *t,int4 ind)
: AddrSpace(m,t,IPTR_IOP,nm,sizeof(void *),1,ind,0,1) : AddrSpace(m,t,IPTR_IOP,NAME,sizeof(void *),1,ind,0,1)
{ {
clearFlags(heritaged|does_deadcode|big_endian); clearFlags(heritaged|does_deadcode|big_endian);
if (HOST_ENDIAN==1) // Endianness always set to host if (HOST_ENDIAN==1) // Endianness always set to host

View file

@ -31,12 +31,13 @@
/// within the \b fspec space. /// within the \b fspec space.
class IopSpace : public AddrSpace { class IopSpace : public AddrSpace {
public: public:
IopSpace(AddrSpaceManager *m,const Translate *t,const string &nm,int4 ind); IopSpace(AddrSpaceManager *m,const Translate *t,int4 ind);
virtual void saveXmlAttributes(ostream &s,uintb offset) const { s << " space=\"iop\""; } virtual void saveXmlAttributes(ostream &s,uintb offset) const { s << " space=\"iop\""; }
virtual void saveXmlAttributes(ostream &s,uintb offset,int4 size) const { s << " space=\"iop\""; } virtual void saveXmlAttributes(ostream &s,uintb offset,int4 size) const { s << " space=\"iop\""; }
virtual void printRaw(ostream &s,uintb offset) const; virtual void printRaw(ostream &s,uintb offset) const;
virtual void saveXml(ostream &s) const; virtual void saveXml(ostream &s) const;
virtual void restoreXml(const Element *el); virtual void restoreXml(const Element *el);
static const string NAME; ///< Reserved name for the iop space
}; };
/// \brief Lowest level operation of the \b p-code language /// \brief Lowest level operation of the \b p-code language

View file

@ -58,7 +58,7 @@ class PcodeCompile {
AddrSpace *uniqspace; AddrSpace *uniqspace;
uint4 local_labelcount; // Number of labels in current constructor uint4 local_labelcount; // Number of labels in current constructor
bool enforceLocalKey; // Force slaspec to use 'local' keyword when defining temporary varnodes bool enforceLocalKey; // Force slaspec to use 'local' keyword when defining temporary varnodes
virtual uintb allocateTemp(void)=0; virtual uint4 allocateTemp(void)=0;
virtual void addSymbol(SleighSymbol *sym)=0; virtual void addSymbol(SleighSymbol *sym)=0;
public: public:
PcodeCompile(void) { defaultspace=(AddrSpace *)0; constantspace=(AddrSpace *)0; PcodeCompile(void) { defaultspace=(AddrSpace *)0; constantspace=(AddrSpace *)0;

View file

@ -162,7 +162,7 @@ public:
class PcodeInjectLibrary { class PcodeInjectLibrary {
protected: protected:
Architecture *glb; ///< The Architecture to which the injection payloads apply Architecture *glb; ///< The Architecture to which the injection payloads apply
uintb tempbase; ///< Offset within \e unique space for allocating temporaries within a payload uint4 tempbase; ///< Offset within \e unique space for allocating temporaries within a payload
vector<InjectPayload *> injection; ///< Registered injections vector<InjectPayload *> injection; ///< Registered injections
map<string,int4> callFixupMap; ///< Map of registered call-fixup names to injection id map<string,int4> callFixupMap; ///< Map of registered call-fixup names to injection id
map<string,int4> callOtherFixupMap; ///< Map of registered callother-fixup names to injection id map<string,int4> callOtherFixupMap; ///< Map of registered callother-fixup names to injection id
@ -195,9 +195,9 @@ protected:
/// \param injectid is the id of the InjectPayload to finalize /// \param injectid is the id of the InjectPayload to finalize
virtual void registerInject(int4 injectid)=0; virtual void registerInject(int4 injectid)=0;
public: public:
PcodeInjectLibrary(Architecture *g,uintb tmpbase) { glb = g; tempbase = tmpbase; } ///< Constructor PcodeInjectLibrary(Architecture *g,uint4 tmpbase) { glb = g; tempbase = tmpbase; } ///< Constructor
virtual ~PcodeInjectLibrary(void); ///< Destructor virtual ~PcodeInjectLibrary(void); ///< Destructor
uintb getUniqueBase(void) const { return tempbase; } ///< Get the (current) offset for building temporary registers uint4 getUniqueBase(void) const { return tempbase; } ///< Get the (current) offset for building temporary registers
int4 getPayloadId(int4 type,const string &nm) const; ///< Map name and type to the payload id int4 getPayloadId(int4 type,const string &nm) const; ///< Map name and type to the payload id
InjectPayload *getPayload(int4 id) const { return injection[id]; } ///< Get the InjectPayload by id InjectPayload *getPayload(int4 id) const { return injection[id]; } ///< Get the InjectPayload by id
string getCallFixupName(int4 injectid) const; ///< Get the call-fixup name associated with an id string getCallFixupName(int4 injectid) const; ///< Get the call-fixup name associated with an id

View file

@ -3236,10 +3236,10 @@ void PcodeLexer::initialize(istream *t)
} }
} }
uintb PcodeSnippet::allocateTemp(void) uint4 PcodeSnippet::allocateTemp(void)
{ // Allocate a variable in the unique space and return the offset { // Allocate a variable in the unique space and return the offset
uintb res = tempbase; uint4 res = tempbase;
tempbase += 16; tempbase += 16;
return res; return res;
} }

View file

@ -71,11 +71,11 @@ class PcodeSnippet : public PcodeCompile {
PcodeLexer lexer; PcodeLexer lexer;
const SleighBase *sleigh; // Language from which we get symbols const SleighBase *sleigh; // Language from which we get symbols
SymbolTree tree; // Symbols in the local scope of the snippet (temporaries) SymbolTree tree; // Symbols in the local scope of the snippet (temporaries)
uintb tempbase; uint4 tempbase;
int4 errorcount; int4 errorcount;
string firsterror; string firsterror;
ConstructTpl *result; ConstructTpl *result;
virtual uintb allocateTemp(void); virtual uint4 allocateTemp(void);
virtual void addSymbol(SleighSymbol *sym); virtual void addSymbol(SleighSymbol *sym);
public: public:
PcodeSnippet(const SleighBase *slgh); PcodeSnippet(const SleighBase *slgh);
@ -87,8 +87,8 @@ public:
virtual void reportWarning(const Location *loc, const string &msg) {} virtual void reportWarning(const Location *loc, const string &msg) {}
bool hasErrors(void) const { return (errorcount != 0); } bool hasErrors(void) const { return (errorcount != 0); }
const string getErrorMessage(void) const { return firsterror; } const string getErrorMessage(void) const { return firsterror; }
void setUniqueBase(uintb val) { tempbase = val; } void setUniqueBase(uint4 val) { tempbase = val; }
uintb getUniqueBase(void) const { return tempbase; } uint4 getUniqueBase(void) const { return tempbase; }
void clear(void); void clear(void);
int lex(void); int lex(void);
bool parseStream(istream& s); bool parseStream(istream& s);

View file

@ -186,6 +186,30 @@ AddrSpace *SleighBuilder::generatePointer(const VarnodeTpl *vntpl,VarnodeData &v
return hand.space; return hand.space;
} }
void SleighBuilder::generatePointerAdd(PcodeData *op,const VarnodeTpl *vntpl)
{
uintb offsetPlus = vntpl->getOffset().getReal() & 0xffff;
if (offsetPlus == 0) {
return;
}
PcodeData *nextop = cache->allocateInstruction();
nextop->opc = op->opc;
nextop->invar = op->invar;
nextop->isize = op->isize;
nextop->outvar = op->outvar;
op->isize = 2;
op->opc = CPUI_INT_ADD;
VarnodeData *newparams = op->invar = cache->allocateVarnodes(2);
newparams[0] = nextop->invar[1];
newparams[1].space = const_space; // Add in V_OFFSET_PLUS
newparams[1].offset = offsetPlus;
newparams[1].size = newparams[0].size;
op->outvar = nextop->invar + 1; // Output of ADD is input to original op
op->outvar->space = uniq_space; // Result of INT_ADD in special runtime temp
op->outvar->offset = uniq_space->getTrans()->getUniqueStart(Translate::RUNTIME_BITRANGE_EA);
}
void SleighBuilder::dump(OpTpl *op) void SleighBuilder::dump(OpTpl *op)
{ // Dump on op through low-level dump interface { // Dump on op through low-level dump interface
@ -211,6 +235,8 @@ void SleighBuilder::dump(OpTpl *op)
loadvars[0].space = const_space; loadvars[0].space = const_space;
loadvars[0].offset = (uintb)(uintp)spc; loadvars[0].offset = (uintb)(uintp)spc;
loadvars[0].size = sizeof(spc); loadvars[0].size = sizeof(spc);
if (vn->getOffset().getSelect() == ConstTpl::v_offset_plus)
generatePointerAdd(load_op, vn);
} }
else else
generateLocation(vn,invars[i]); generateLocation(vn,invars[i]);
@ -238,6 +264,8 @@ void SleighBuilder::dump(OpTpl *op)
storevars[0].space = const_space; storevars[0].space = const_space;
storevars[0].offset = (uintb)(uintp)spc; // space in which to store storevars[0].offset = (uintb)(uintp)spc; // space in which to store
storevars[0].size = sizeof(spc); storevars[0].size = sizeof(spc);
if (outvn->getOffset().getSelect() == ConstTpl::v_offset_plus)
generatePointerAdd(store_op,outvn);
} }
else { else {
thisop->outvar = cache->allocateVarnodes(1); thisop->outvar = cache->allocateVarnodes(1);

View file

@ -136,6 +136,7 @@ class SleighBuilder : public PcodeBuilder {
void buildEmpty(Constructor *ct,int4 secnum); void buildEmpty(Constructor *ct,int4 secnum);
void generateLocation(const VarnodeTpl *vntpl,VarnodeData &vn); void generateLocation(const VarnodeTpl *vntpl,VarnodeData &vn);
AddrSpace *generatePointer(const VarnodeTpl *vntpl,VarnodeData &vn); AddrSpace *generatePointer(const VarnodeTpl *vntpl,VarnodeData &vn);
void generatePointerAdd(PcodeData *op,const VarnodeTpl *vntpl);
void setUniqueOffset(const Address &addr); ///< Set uniquifying bits for the current instruction void setUniqueOffset(const Address &addr); ///< Set uniquifying bits for the current instruction
public: public:
SleighBuilder(ParserWalker *w,DisassemblyCache *dcache,PcodeCacher *pc,AddrSpace *cspc,AddrSpace *uspc,uint4 umask); SleighBuilder(ParserWalker *w,DisassemblyCache *dcache,PcodeCacher *pc,AddrSpace *cspc,AddrSpace *uspc,uint4 umask);

View file

@ -161,7 +161,7 @@ PcodeInjectLibrary *SleighArchitecture::buildPcodeInjectLibrary(void)
{ // Build the pcode injector based on sleigh { // Build the pcode injector based on sleigh
PcodeInjectLibrary *res; PcodeInjectLibrary *res;
res = new PcodeInjectLibrarySleigh(this,translate->getUniqueBase()); res = new PcodeInjectLibrarySleigh(this);
return res; return res;
} }

View file

@ -17,7 +17,7 @@
const int4 SleighBase::SLA_FORMAT_VERSION = 3; const int4 SleighBase::SLA_FORMAT_VERSION = 3;
const uintb SleighBase::MAX_UNIQUE_SIZE = 128; const uint4 SleighBase::MAX_UNIQUE_SIZE = 128;
int4 SourceFileIndexer::index(const string filename){ int4 SourceFileIndexer::index(const string filename){
auto it = fileToIndex.find(filename); auto it = fileToIndex.find(filename);

View file

@ -69,7 +69,7 @@ protected:
void reregisterContext(void); ///< Reregister context fields for a new executable void reregisterContext(void); ///< Reregister context fields for a new executable
void restoreXml(const Element *el); ///< Read a SLEIGH specification from XML void restoreXml(const Element *el); ///< Read a SLEIGH specification from XML
public: public:
static const uintb MAX_UNIQUE_SIZE; ///< Maximum size of a varnode in the unique space (should match value in SleighBase.java) static const uint4 MAX_UNIQUE_SIZE; ///< Maximum size of a varnode in the unique space (should match value in SleighBase.java)
SleighBase(void); ///< Construct an uninitialized translator SleighBase(void); ///< Construct an uninitialized translator
bool isInitialized(void) const { return (root != (SubtableSymbol *)0); } ///< Return \b true if \b this is initialized bool isInitialized(void) const { return (root != (SubtableSymbol *)0); } ///< Return \b true if \b this is initialized
virtual ~SleighBase(void) {} ///< Destructor virtual ~SleighBase(void) {} ///< Destructor

View file

@ -1739,7 +1739,7 @@ void MacroBuilder::setLabel(OpTpl *op)
outvec.push_back(clone); outvec.push_back(clone);
} }
uintb SleighPcode::allocateTemp(void) uint4 SleighPcode::allocateTemp(void)
{ {
return compiler->getUniqueAddr(); return compiler->getUniqueAddr();
@ -1799,14 +1799,14 @@ void SleighCompile::predefinedSymbols(void)
// Some predefined symbols // Some predefined symbols
root = new SubtableSymbol("instruction"); // Base constructors root = new SubtableSymbol("instruction"); // Base constructors
symtab.addSymbol(root); symtab.addSymbol(root);
insertSpace(new ConstantSpace(this,this,"const",AddrSpace::constant_space_index)); insertSpace(new ConstantSpace(this,this));
SpaceSymbol *spacesym = new SpaceSymbol(getConstantSpace()); // Constant space SpaceSymbol *spacesym = new SpaceSymbol(getConstantSpace()); // Constant space
symtab.addSymbol(spacesym); symtab.addSymbol(spacesym);
OtherSpace *otherSpace = new OtherSpace(this,this,"OTHER",AddrSpace::other_space_index); OtherSpace *otherSpace = new OtherSpace(this,this,OtherSpace::INDEX);
insertSpace(otherSpace); insertSpace(otherSpace);
spacesym = new SpaceSymbol(otherSpace); spacesym = new SpaceSymbol(otherSpace);
symtab.addSymbol(spacesym); symtab.addSymbol(spacesym);
insertSpace(new UniqueSpace(this,this,"unique",numSpaces(),0)); insertSpace(new UniqueSpace(this,this,numSpaces(),0));
spacesym = new SpaceSymbol(getUniqueSpace()); // Temporary register space spacesym = new SpaceSymbol(getUniqueSpace()); // Temporary register space
symtab.addSymbol(spacesym); symtab.addSymbol(spacesym);
StartSymbol *startsym = new StartSymbol("inst_start",getConstantSpace()); StartSymbol *startsym = new StartSymbol("inst_start",getConstantSpace());
@ -2271,10 +2271,10 @@ void SleighCompile::reportWarning(const string &msg)
/// this method does not make an assumption about the size of the requested temporary Varnode. /// this method does not make an assumption about the size of the requested temporary Varnode.
/// It reserves a fixed amount of space and returns its starting offset. /// It reserves a fixed amount of space and returns its starting offset.
/// \return the starting offset of the new temporary register /// \return the starting offset of the new temporary register
uintb SleighCompile::getUniqueAddr(void) uint4 SleighCompile::getUniqueAddr(void)
{ {
uintb base = getUniqueBase(); uint4 base = getUniqueBase();
setUniqueBase(base + SleighBase::MAX_UNIQUE_SIZE); setUniqueBase(base + SleighBase::MAX_UNIQUE_SIZE);
return base; return base;
} }
@ -3422,7 +3422,7 @@ void SleighCompile::checkUniqueAllocation(void)
if (i>=tables.size()) break; if (i>=tables.size()) break;
sym = tables[i]; sym = tables[i];
} }
uintm ubase = getUniqueBase(); // We have to adjust the unique base uint4 ubase = getUniqueBase(); // We have to adjust the unique base
ubase <<= sa; ubase <<= sa;
setUniqueBase(ubase); setUniqueBase(ubase);
} }

View file

@ -246,7 +246,7 @@ public:
/// parser. /// parser.
class SleighPcode : public PcodeCompile { class SleighPcode : public PcodeCompile {
SleighCompile *compiler; ///< The main SLEIGH parser SleighCompile *compiler; ///< The main SLEIGH parser
virtual uintb allocateTemp(void); virtual uint4 allocateTemp(void);
virtual const Location *getLocation(SleighSymbol *sym) const; virtual const Location *getLocation(SleighSymbol *sym) const;
virtual void reportError(const Location* loc, const string &msg); virtual void reportError(const Location* loc, const string &msg);
virtual void reportWarning(const Location* loc, const string &msg); virtual void reportWarning(const Location* loc, const string &msg);
@ -332,7 +332,7 @@ public:
void reportWarning(const Location *loc, const string &msg); ///< Issue a warning message with a source location void reportWarning(const Location *loc, const string &msg); ///< Issue a warning message with a source location
int4 numErrors(void) const { return errors; } ///< Return the current number of fatal errors int4 numErrors(void) const { return errors; } ///< Return the current number of fatal errors
uintb getUniqueAddr(void); ///< Get the next available temporary register offset uint4 getUniqueAddr(void); ///< Get the next available temporary register offset
/// \brief Set whether unnecessary truncation and extension operators generate warnings individually /// \brief Set whether unnecessary truncation and extension operators generate warnings individually
/// ///

View file

@ -350,16 +350,17 @@ void AddrSpace::restoreXml(const Element *el)
calcScaleMask(); calcScaleMask();
} }
const string ConstantSpace::NAME = "const";
const int4 ConstantSpace::INDEX = 0;
/// This constructs the unique constant space /// This constructs the unique constant space
/// By convention, the name is always "const" and the index /// By convention, the name is always "const" and the index
/// is always 0. /// is always 0.
/// \param m is the associated address space manager /// \param m is the associated address space manager
/// \param t is the associated processor translator /// \param t is the associated processor translator
/// \param nm is the name ConstantSpace::ConstantSpace(AddrSpaceManager *m,const Translate *t)
/// \param ind is the integer identifier : AddrSpace(m,t,IPTR_CONSTANT,NAME,sizeof(uintb),1,INDEX,0,0)
ConstantSpace::ConstantSpace(AddrSpaceManager *m,const Translate *t,
const string &nm,int4 ind)
: AddrSpace(m,t,IPTR_CONSTANT,nm,sizeof(uintb),1,ind,0,0)
{ {
clearFlags(heritaged|does_deadcode|big_endian); clearFlags(heritaged|does_deadcode|big_endian);
if (HOST_ENDIAN==1) // Endianness always matches host if (HOST_ENDIAN==1) // Endianness always matches host
@ -390,16 +391,18 @@ void ConstantSpace::restoreXml(const Element *el)
throw LowlevelError("Should never restore the constant space from XML"); throw LowlevelError("Should never restore the constant space from XML");
} }
const string OtherSpace::NAME = "OTHER";
const int4 OtherSpace::INDEX = 1;
/// Construct the \b other space, which is automatically constructed /// Construct the \b other space, which is automatically constructed
/// by the compiler, and is only constructed once. The name should /// by the compiler, and is only constructed once. The name should
/// always by \b OTHER. /// always by \b OTHER.
/// \param m is the associated address space manager /// \param m is the associated address space manager
/// \param t is the associated processor translator /// \param t is the associated processor translator
/// \param nm is the name of the space
/// \param ind is the integer identifier /// \param ind is the integer identifier
OtherSpace::OtherSpace(AddrSpaceManager *m,const Translate *t, OtherSpace::OtherSpace(AddrSpaceManager *m,const Translate *t,int4 ind)
const string &nm,int4 ind) : AddrSpace(m,t,IPTR_PROCESSOR,NAME,sizeof(uintb),1,INDEX,0,0)
: AddrSpace(m,t,IPTR_PROCESSOR,nm,sizeof(uintb),1,ind,0,0)
{ {
clearFlags(heritaged|does_deadcode); clearFlags(heritaged|does_deadcode);
setFlags(is_otherspace); setFlags(is_otherspace);
@ -426,17 +429,19 @@ void OtherSpace::saveXml(ostream &s) const
s << "/>\n"; s << "/>\n";
} }
const string UniqueSpace::NAME = "unique";
const uint4 UniqueSpace::SIZE = 4;
/// This is the constructor for the \b unique space, which is /// This is the constructor for the \b unique space, which is
/// automatically constructed by the analysis engine, and /// automatically constructed by the analysis engine, and
/// constructed only once. The name should always be \b unique. /// constructed only once. The name should always be \b unique.
/// \param m is the associated address space manager /// \param m is the associated address space manager
/// \param t is the associated processor translator /// \param t is the associated processor translator
/// \param nm is the name of the space
/// \param ind is the integer identifier /// \param ind is the integer identifier
/// \param fl are attribute flags (currently unused) /// \param fl are attribute flags (currently unused)
UniqueSpace::UniqueSpace(AddrSpaceManager *m,const Translate *t,const string &nm, UniqueSpace::UniqueSpace(AddrSpaceManager *m,const Translate *t,int4 ind,uint4 fl)
int4 ind,uint4 fl) : AddrSpace(m,t,IPTR_INTERNAL,NAME,SIZE,1,ind,fl,0)
: AddrSpace(m,t,IPTR_INTERNAL,nm,sizeof(uintm),1,ind,fl,0)
{ {
setFlags(hasphysical); setFlags(hasphysical);
} }
@ -455,14 +460,15 @@ void UniqueSpace::saveXml(ostream &s) const
s << "/>\n"; s << "/>\n";
} }
const string JoinSpace::NAME = "join";
/// This is the constructor for the \b join space, which is automatically constructed by the /// This is the constructor for the \b join space, which is automatically constructed by the
/// analysis engine, and constructed only once. The name should always be \b join. /// analysis engine, and constructed only once. The name should always be \b join.
/// \param m is the associated address space manager /// \param m is the associated address space manager
/// \param t is the associated processor translator /// \param t is the associated processor translator
/// \param nm is the name of the space
/// \param ind is the integer identifier /// \param ind is the integer identifier
JoinSpace::JoinSpace(AddrSpaceManager *m,const Translate *t,const string &nm,int4 ind) JoinSpace::JoinSpace(AddrSpaceManager *m,const Translate *t,int4 ind)
: AddrSpace(m,t,IPTR_JOIN,nm,sizeof(uintm),1,ind,0,0) : AddrSpace(m,t,IPTR_JOIN,NAME,sizeof(uintm),1,ind,0,0)
{ {
// This is a virtual space // This is a virtual space
// setFlags(hasphysical); // setFlags(hasphysical);

View file

@ -86,10 +86,6 @@ public:
is_otherspace = 512, ///< Quick check for the OtherSpace derived class is_otherspace = 512, ///< Quick check for the OtherSpace derived class
has_nearpointers = 0x400 ///< Does there exist near pointers into this space has_nearpointers = 0x400 ///< Does there exist near pointers into this space
}; };
enum {
constant_space_index = 0, ///< Reserved index for the constant space
other_space_index = 1 ///< Reserved index for the other space
};
private: private:
spacetype type; ///< Type of space (PROCESSOR, CONSTANT, INTERNAL, ...) spacetype type; ///< Type of space (PROCESSOR, CONSTANT, INTERNAL, ...)
AddrSpaceManager *manage; ///< Manager for processor using this space AddrSpaceManager *manage; ///< Manager for processor using this space
@ -178,19 +174,23 @@ public:
/// by the offset field of an Address. /// by the offset field of an Address.
class ConstantSpace : public AddrSpace { class ConstantSpace : public AddrSpace {
public: public:
ConstantSpace(AddrSpaceManager *m,const Translate *t,const string &nm,int4 ind); ///< Only constructor ConstantSpace(AddrSpaceManager *m,const Translate *t); ///< Only constructor
virtual void printRaw(ostream &s,uintb offset) const; virtual void printRaw(ostream &s,uintb offset) const;
virtual void saveXml(ostream &s) const; virtual void saveXml(ostream &s) const;
virtual void restoreXml(const Element *el); virtual void restoreXml(const Element *el);
static const string NAME; // Reserved name for the address space
static const int4 INDEX; // Reserved index for constant space
}; };
/// \brief Special AddrSpace for special/user-defined address spaces /// \brief Special AddrSpace for special/user-defined address spaces
class OtherSpace : public AddrSpace { class OtherSpace : public AddrSpace {
public: public:
OtherSpace(AddrSpaceManager *m, const Translate *t, const string &nm, int4 ind); ///< Constructor OtherSpace(AddrSpaceManager *m, const Translate *t, int4 ind); ///< Constructor
OtherSpace(AddrSpaceManager *m, const Translate *t); ///< For use with restoreXml OtherSpace(AddrSpaceManager *m, const Translate *t); ///< For use with restoreXml
virtual void printRaw(ostream &s, uintb offset) const; virtual void printRaw(ostream &s, uintb offset) const;
virtual void saveXml(ostream &s) const; virtual void saveXml(ostream &s) const;
static const string NAME; // Reserved name for the address space
static const int4 INDEX; // Reserved index for the other space
}; };
/// \brief The pool of temporary storage registers /// \brief The pool of temporary storage registers
@ -204,9 +204,11 @@ public:
/// \b unique. /// \b unique.
class UniqueSpace : public AddrSpace { class UniqueSpace : public AddrSpace {
public: public:
UniqueSpace(AddrSpaceManager *m,const Translate *t,const string &nm,int4 ind,uint4 fl); ///< Constructor UniqueSpace(AddrSpaceManager *m,const Translate *t,int4 ind,uint4 fl); ///< Constructor
UniqueSpace(AddrSpaceManager *m,const Translate *t); ///< For use with restoreXml UniqueSpace(AddrSpaceManager *m,const Translate *t); ///< For use with restoreXml
virtual void saveXml(ostream &s) const; virtual void saveXml(ostream &s) const;
static const string NAME; ///< Reserved name for the unique space
static const uint4 SIZE; ///< Fixed size (in bytes) for unique space offsets
}; };
/// \brief The pool of logically joined variables /// \brief The pool of logically joined variables
@ -219,7 +221,7 @@ public:
/// have an absolute meaning, the database may vary what offset is assigned to what set of pieces. /// have an absolute meaning, the database may vary what offset is assigned to what set of pieces.
class JoinSpace : public AddrSpace { class JoinSpace : public AddrSpace {
public: public:
JoinSpace(AddrSpaceManager *m,const Translate *t,const string &nm,int4 ind); JoinSpace(AddrSpaceManager *m,const Translate *t,int4 ind);
virtual void saveXmlAttributes(ostream &s,uintb offset) const; virtual void saveXmlAttributes(ostream &s,uintb offset) const;
virtual void saveXmlAttributes(ostream &s,uintb offset,int4 size) const; virtual void saveXmlAttributes(ostream &s,uintb offset,int4 size) const;
virtual uintb restoreXmlAttributes(const Element *el,uint4 &size) const; virtual uintb restoreXmlAttributes(const Element *el,uint4 &size) const;
@ -227,6 +229,7 @@ public:
virtual uintb read(const string &s,int4 &size) const; virtual uintb read(const string &s,int4 &size) const;
virtual void saveXml(ostream &s) const; virtual void saveXml(ostream &s) const;
virtual void restoreXml(const Element *el); virtual void restoreXml(const Element *el);
static const string NAME; ///< Reserved name for the join space
}; };
/// \brief An overlay space. /// \brief An overlay space.

View file

@ -229,7 +229,7 @@ void AddrSpaceManager::restoreXmlSpaces(const Element *el,const Translate *trans
{ {
// The first space should always be the constant space // The first space should always be the constant space
insertSpace(new ConstantSpace(this,trans,"const",AddrSpace::constant_space_index)); insertSpace(new ConstantSpace(this,trans));
string defname(el->getAttributeValue("defaultspace")); string defname(el->getAttributeValue("defaultspace"));
const List &list(el->getChildren()); const List &list(el->getChildren());
@ -302,14 +302,14 @@ void AddrSpaceManager::insertSpace(AddrSpace *spc)
bool duplicateId = false; bool duplicateId = false;
switch(spc->getType()) { switch(spc->getType()) {
case IPTR_CONSTANT: case IPTR_CONSTANT:
if (spc->getName() != "const") if (spc->getName() != ConstantSpace::NAME)
nameTypeMismatch = true; nameTypeMismatch = true;
if (spc->index != AddrSpace::constant_space_index) if (spc->index != ConstantSpace::INDEX)
throw LowlevelError("const space must be assigned index 0"); throw LowlevelError("const space must be assigned index 0");
constantspace = spc; constantspace = spc;
break; break;
case IPTR_INTERNAL: case IPTR_INTERNAL:
if (spc->getName() != "unique") if (spc->getName() != UniqueSpace::NAME)
nameTypeMismatch = true; nameTypeMismatch = true;
if (uniqspace != (AddrSpace *)0) if (uniqspace != (AddrSpace *)0)
duplicateName = true; duplicateName = true;
@ -323,7 +323,7 @@ void AddrSpaceManager::insertSpace(AddrSpace *spc)
fspecspace = spc; fspecspace = spc;
break; break;
case IPTR_JOIN: case IPTR_JOIN:
if (spc->getName() != "join") if (spc->getName() != JoinSpace::NAME)
nameTypeMismatch = true; nameTypeMismatch = true;
if (joinspace != (AddrSpace *)0) if (joinspace != (AddrSpace *)0)
duplicateName = true; duplicateName = true;
@ -349,7 +349,7 @@ void AddrSpaceManager::insertSpace(AddrSpace *spc)
ospc->getBaseSpace()->setFlags(AddrSpace::overlaybase); // Mark the base as being overlayed ospc->getBaseSpace()->setFlags(AddrSpace::overlaybase); // Mark the base as being overlayed
} }
else if (spc->isOtherSpace()) { else if (spc->isOtherSpace()) {
if (spc->index != AddrSpace::other_space_index) if (spc->index != OtherSpace::INDEX)
throw LowlevelError("OTHER space must be assigned index 1"); throw LowlevelError("OTHER space must be assigned index 1");
} }
break; break;

View file

@ -292,21 +292,32 @@ public:
/// with the processor. In particular, it knows about all the /// with the processor. In particular, it knows about all the
/// address spaces, registers, and spacebases for the processor. /// address spaces, registers, and spacebases for the processor.
class Translate : public AddrSpaceManager { class Translate : public AddrSpaceManager {
public:
/// Tagged addresses in the \e unique address space
enum UniqueLayout {
RUNTIME_BOOLEAN_INVERT=0, ///< Location of the runtime temporary for boolean inversion
RUNTIME_RETURN_LOCATION=0x80, ///< Location of the runtime temporary storing the return value
RUNTIME_BITRANGE_EA=0x100, ///< Location of the runtime temporary for storing an effective address
INJECT=0x200, ///< Range of temporaries for use in compiling p-code snippets
ANALYSIS=0x10000000 ///< Range of temporaries for use during decompiler analysis
};
private:
bool target_isbigendian; ///< \b true if the general endianness of the process is big endian bool target_isbigendian; ///< \b true if the general endianness of the process is big endian
uintm unique_base; ///< Starting offset into unique space uint4 unique_base; ///< Starting offset into unique space
protected: protected:
int4 alignment; ///< Byte modulo on which instructions are aligned int4 alignment; ///< Byte modulo on which instructions are aligned
vector<FloatFormat> floatformats; ///< Floating point formats utilized by the processor vector<FloatFormat> floatformats; ///< Floating point formats utilized by the processor
void setBigEndian(bool val); ///< Set general endianness to \b big if val is \b true void setBigEndian(bool val); ///< Set general endianness to \b big if val is \b true
void setUniqueBase(uintm val); ///< Set the base offset for new temporary registers void setUniqueBase(uint4 val); ///< Set the base offset for new temporary registers
public: public:
Translate(void); ///< Constructor for the translator Translate(void); ///< Constructor for the translator
void setDefaultFloatFormats(void); ///< If no explicit float formats, set up default formats void setDefaultFloatFormats(void); ///< If no explicit float formats, set up default formats
bool isBigEndian(void) const; ///< Is the processor big endian? bool isBigEndian(void) const; ///< Is the processor big endian?
const FloatFormat *getFloatFormat(int4 size) const; ///< Get format for a particular floating point encoding const FloatFormat *getFloatFormat(int4 size) const; ///< Get format for a particular floating point encoding
int4 getAlignment(void) const; ///< Get the instruction alignment for the processor int4 getAlignment(void) const; ///< Get the instruction alignment for the processor
uintm getUniqueBase(void) const; ///< Get the base offset for new temporary registers uint4 getUniqueBase(void) const; ///< Get the base offset for new temporary registers
uint4 getUniqueStart(UniqueLayout layout) const; ///< Get a tagged address within the \e unique space
/// \brief Initialize the translator given XML configuration documents /// \brief Initialize the translator given XML configuration documents
/// ///
@ -551,7 +562,7 @@ inline void Translate::setBigEndian(bool val) {
/// for the pcode engine, and sets the base offset where registers /// for the pcode engine, and sets the base offset where registers
/// created by the simplification process can start being allocated. /// created by the simplification process can start being allocated.
/// \param val is the boundary offset /// \param val is the boundary offset
inline void Translate::setUniqueBase(uintm val) { inline void Translate::setUniqueBase(uint4 val) {
if (val>unique_base) unique_base = val; if (val>unique_base) unique_base = val;
} }
@ -573,14 +584,19 @@ inline int4 Translate::getAlignment(void) const {
return alignment; return alignment;
} }
/// This routine gets the base offset, within the \e unique /// Return the first offset within the \e unique space after the range statically reserved by Translate.
/// temporary register space, where new registers can be /// This is generally the starting offset where dynamic temporary registers can start to be allocated.
/// allocated for the simplification process. Locations before
/// this offset are reserved registers needed by the pcode
/// translation engine.
/// \return the first allocatable offset /// \return the first allocatable offset
inline uintm Translate::getUniqueBase(void) const { inline uint4 Translate::getUniqueBase(void) const {
return unique_base; return unique_base;
} }
/// Regions of the \e unique space are reserved for specific uses. We select the start of a specific
/// region based on the given tag.
/// \param layout is the given tag
/// \return the absolute offset into the \e unique space
inline uint4 Translate::getUniqueStart(UniqueLayout layout) const {
return (layout != ANALYSIS) ? layout + unique_base : layout;
}
#endif #endif

View file

@ -852,17 +852,15 @@ void Varnode::printRaw(ostream &s,const Varnode *vn)
} }
/// \param m is the underlying address space manager /// \param m is the underlying address space manager
/// \param uspace is the \e unique space VarnodeBank::VarnodeBank(AddrSpaceManager *m)
/// \param ubase is the base offset for allocating temporaries
VarnodeBank::VarnodeBank(AddrSpaceManager *m,AddrSpace *uspace,uintm ubase)
: searchvn(0,Address(Address::m_minimal),(Datatype *)0) : searchvn(0,Address(Address::m_minimal),(Datatype *)0)
{ {
manage = m; manage = m;
searchvn.flags = Varnode::input; // searchvn is always an input varnode of size 0 searchvn.flags = Varnode::input; // searchvn is always an input varnode of size 0
uniq_space = uspace; uniq_space = m->getUniqueSpace();
uniqbase = ubase; uniqbase = uniq_space->getTrans()->getUniqueStart(Translate::ANALYSIS);
uniqid = ubase; uniqid = uniqbase;
create_index = 0; create_index = 0;
} }

View file

@ -339,7 +339,7 @@ class VarnodeBank {
mutable Varnode searchvn; ///< Template varnode for searching trees mutable Varnode searchvn; ///< Template varnode for searching trees
Varnode *xref(Varnode *vn); ///< Insert a Varnode into the sorted lists Varnode *xref(Varnode *vn); ///< Insert a Varnode into the sorted lists
public: public:
VarnodeBank(AddrSpaceManager *m,AddrSpace *uspace,uintm ubase); ///< Construct the container VarnodeBank(AddrSpaceManager *m); ///< Construct the container
void clear(void); ///< Clear out all Varnodes and reset counters void clear(void); ///< Clear out all Varnodes and reset counters
~VarnodeBank(void) { clear(); } ///< Destructor ~VarnodeBank(void) { clear(); } ///< Destructor
int4 numVarnodes(void) const { return loc_tree.size(); } ///< Get number of Varnodes \b this contains int4 numVarnodes(void) const { return loc_tree.size(); } ///< Get number of Varnodes \b this contains

View file

@ -25,6 +25,7 @@ import java.io.*;
import generic.jar.ResourceFile; import generic.jar.ResourceFile;
import ghidra.app.plugin.processors.sleigh.SleighLanguage; import ghidra.app.plugin.processors.sleigh.SleighLanguage;
import ghidra.app.plugin.processors.sleigh.UniqueLayout;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressFactory; import ghidra.program.model.address.AddressFactory;
import ghidra.program.model.lang.*; import ghidra.program.model.lang.*;
@ -212,9 +213,7 @@ public class DecompInterface {
DecompileProcessFactory.release(decompProcess); DecompileProcessFactory.release(decompProcess);
decompProcess = DecompileProcessFactory.get(); decompProcess = DecompileProcessFactory.get();
} }
// use static uniqueBase since we don't know how many dynamically generated long uniqueBase = UniqueLayout.SLEIGH_BASE.getOffset(pcodelanguage);
// variables Ghidra may add to the language/compile-spec uniqueBase
long uniqueBase = 0x10000000;
String tspec = String tspec =
pcodelanguage.buildTranslatorTag(program.getAddressFactory(), uniqueBase, null); pcodelanguage.buildTranslatorTag(program.getAddressFactory(), uniqueBase, null);
String coretypes = dtmanage.buildCoreTypes(); String coretypes = dtmanage.buildCoreTypes();

View file

@ -67,7 +67,6 @@ public class DecompileCallback {
private DecompileDebug debug; private DecompileDebug debug;
private Program program; private Program program;
private Listing listing; private Listing listing;
private UniqueAddressFactory uniqueFactory;
private Function cachedFunction; private Function cachedFunction;
private AddressSet undefinedBody; private AddressSet undefinedBody;
private Address funcEntry; private Address funcEntry;
@ -88,7 +87,6 @@ public class DecompileCallback {
PcodeDataTypeManager dt) { PcodeDataTypeManager dt) {
program = prog; program = prog;
pcodelanguage = language; pcodelanguage = language;
uniqueFactory = new UniqueAddressFactory(prog.getAddressFactory(), language);
pcodecompilerspec = compilerSpec; pcodecompilerspec = compilerSpec;
listing = program.getListing(); listing = program.getListing();
addrfactory = program.getAddressFactory(); addrfactory = program.getAddressFactory();
@ -138,7 +136,6 @@ public class DecompileCallback {
if (pseudoDisassembler != null) { if (pseudoDisassembler != null) {
pseudoDisassembler.resetDisassemblerContext(); pseudoDisassembler.resetDisassemblerContext();
} }
uniqueFactory.reset();
} }
/** /**
@ -294,7 +291,7 @@ public class DecompileCallback {
PackedBytes pcode = instr.getPrototype() PackedBytes pcode = instr.getPrototype()
.getPcodePacked(instr.getInstructionContext(), .getPcodePacked(instr.getInstructionContext(),
new InstructionPcodeOverride(instr), uniqueFactory); new InstructionPcodeOverride(instr));
return pcode; return pcode;
} }

View file

@ -49,10 +49,10 @@ public abstract class PcodeEmit {
private Address defaultFallAddress; private Address defaultFallAddress;
private Address fallOverride; private Address fallOverride;
private int fallOffset; private int fallOffset;
private UniqueAddressFactory uniqueFactory; private SleighLanguage language;
private AddressFactory addressFactory;
private VarnodeData outcache; private VarnodeData outcache;
protected VarnodeData[] incache; protected VarnodeData[] incache;
private VarnodeData[] dyncache;
protected ArrayList<Integer> labeldef = null; protected ArrayList<Integer> labeldef = null;
protected int numOps = 0; // Number of PcodeOps generated so far protected int numOps = 0; // Number of PcodeOps generated so far
private int labelbase = 0; private int labelbase = 0;
@ -76,10 +76,9 @@ public abstract class PcodeEmit {
* @param ictx is the InstructionContext interface to resolve requests for context * @param ictx is the InstructionContext interface to resolve requests for context
* @param fallOffset default instruction fall offset (i.e., instruction length including delay slotted instructions) * @param fallOffset default instruction fall offset (i.e., instruction length including delay slotted instructions)
* @param override required if pcode overrides are to be utilized * @param override required if pcode overrides are to be utilized
* @param uniqueFactory required when override specified or if overlay normalization is required
*/ */
public PcodeEmit(ParserWalker walk, InstructionContext ictx, int fallOffset, public PcodeEmit(ParserWalker walk, InstructionContext ictx, int fallOffset,
PcodeOverride override, UniqueAddressFactory uniqueFactory) { PcodeOverride override) {
this.walker = walk; this.walker = walk;
this.parsercontext = walk.getParserContext(); this.parsercontext = walk.getParserContext();
this.instcontext = ictx; this.instcontext = ictx;
@ -88,30 +87,27 @@ public abstract class PcodeEmit {
AddressSpace myspace = startAddress.getAddressSpace(); AddressSpace myspace = startAddress.getAddressSpace();
if (myspace.isOverlaySpace()) { if (myspace.isOverlaySpace()) {
overlayspace = myspace; overlayspace = myspace;
startAddress = ((OverlayAddressSpace) myspace).getOverlayedSpace().getAddress( startAddress = ((OverlayAddressSpace) myspace).getOverlayedSpace()
startAddress.getOffset()); .getAddress(startAddress.getOffset());
} }
this.fallOffset = fallOffset; this.fallOffset = fallOffset;
this.uniqueFactory = uniqueFactory;
this.override = override; this.override = override;
SleighInstructionPrototype sleighproto = parsercontext.getPrototype(); SleighInstructionPrototype sleighproto = parsercontext.getPrototype();
if (sleighproto != null) { if (sleighproto != null) {
SleighLanguage sleighlang = (SleighLanguage) sleighproto.getLanguage(); language = (SleighLanguage) sleighproto.getLanguage();
uniq_space = sleighlang.getAddressFactory().getUniqueSpace(); addressFactory = language.getAddressFactory();
uniquemask = sleighlang.getUniqueAllocationMask(); uniq_space = addressFactory.getUniqueSpace();
uniquemask = language.getUniqueAllocationMask();
uniqueoffset = (startAddress.getOffset() & uniquemask) << 4; uniqueoffset = (startAddress.getOffset() & uniquemask) << 4;
} }
else { // This can happen for CallFixup snippets, but these don't need their temporary vars patched up else { // This can happen for CallFixup snippets, but these don't need their temporary vars patched up
language = null;
uniq_space = null; uniq_space = null;
uniquemask = 0; uniquemask = 0;
uniqueoffset = 0; uniqueoffset = 0;
} }
if (override != null) { if (override != null) {
if (uniqueFactory == null) {
throw new IllegalArgumentException(
"uniqueFactory required when override is specified");
}
flowOverride = override.getFlowOverride(); flowOverride = override.getFlowOverride();
if (flowOverride == FlowOverride.NONE) { if (flowOverride == FlowOverride.NONE) {
flowOverride = null; flowOverride = null;
@ -131,7 +127,6 @@ public abstract class PcodeEmit {
} }
incache = new VarnodeData[8]; // Maximum number of inputs incache = new VarnodeData[8]; // Maximum number of inputs
dyncache = null;
} }
private void setUniqueOffset(Address addr) { private void setUniqueOffset(Address addr) {
@ -159,7 +154,7 @@ public abstract class PcodeEmit {
*/ */
private void setLabel(OpTpl op) { private void setLabel(OpTpl op) {
if (labeldef == null) { if (labeldef == null) {
labeldef = new ArrayList<Integer>(); labeldef = new ArrayList<>();
} }
int labelindex = (int) op.getInput()[0].getOffset().getReal() + labelbase; int labelindex = (int) op.getInput()[0].getOffset().getReal() + labelbase;
while (labeldef.size() <= labelindex) { while (labeldef.size() <= labelindex) {
@ -282,9 +277,11 @@ public abstract class PcodeEmit {
// CALL <dest> // CALL <dest>
// <label> // <label>
Address tmpAddr = uniqueFactory.getNextUniqueAddress(); VarnodeTpl tmp =
VarnodeTpl tmp = new VarnodeTpl(new ConstTpl(tmpAddr.getAddressSpace()), new VarnodeTpl(new ConstTpl(uniq_space),
new ConstTpl(ConstTpl.REAL, tmpAddr.getOffset()), inputs[1].getSize()); new ConstTpl(ConstTpl.REAL,
UniqueLayout.RUNTIME_BOOLEAN_INVERT.getOffset(language)),
inputs[1].getSize());
int labelIndex = labelcount++; int labelIndex = labelcount++;
VarnodeTpl label = new VarnodeTpl(new ConstTpl(const_space), VarnodeTpl label = new VarnodeTpl(new ConstTpl(const_space),
new ConstTpl(ConstTpl.J_RELATIVE, labelIndex), new ConstTpl(ConstTpl.REAL, 8)); new ConstTpl(ConstTpl.J_RELATIVE, labelIndex), new ConstTpl(ConstTpl.REAL, 8));
@ -338,9 +335,9 @@ public abstract class PcodeEmit {
// tmp = COPY &<dest> // tmp = COPY &<dest>
// RETURN tmp // RETURN tmp
Address tmpAddr = uniqueFactory.getNextUniqueAddress(); VarnodeTpl tmp = new VarnodeTpl(new ConstTpl(uniq_space),
VarnodeTpl tmp = new VarnodeTpl(new ConstTpl(tmpAddr.getAddressSpace()), new ConstTpl(ConstTpl.REAL,
new ConstTpl(ConstTpl.REAL, tmpAddr.getOffset()), UniqueLayout.RUNTIME_RETURN_LOCATION.getOffset(language)),
new ConstTpl(ConstTpl.REAL, ptrSize)); new ConstTpl(ConstTpl.REAL, ptrSize));
VarnodeTpl destAddr = new VarnodeTpl(new ConstTpl(const_space), inputs[0].getOffset(), VarnodeTpl destAddr = new VarnodeTpl(new ConstTpl(const_space), inputs[0].getOffset(),
@ -379,13 +376,15 @@ public abstract class PcodeEmit {
// RETURN <dest> // RETURN <dest>
// <label> // <label>
Address tmpAddr = uniqueFactory.getNextUniqueAddress(); VarnodeTpl tmp =
VarnodeTpl tmp = new VarnodeTpl(new ConstTpl(tmpAddr.getAddressSpace()), new VarnodeTpl(new ConstTpl(uniq_space),
new ConstTpl(ConstTpl.REAL, tmpAddr.getOffset()), inputs[1].getSize()); new ConstTpl(ConstTpl.REAL,
UniqueLayout.RUNTIME_BOOLEAN_INVERT.getOffset(language)),
inputs[1].getSize());
tmpAddr = uniqueFactory.getNextUniqueAddress(); VarnodeTpl tmp2 = new VarnodeTpl(new ConstTpl(uniq_space),
VarnodeTpl tmp2 = new VarnodeTpl(new ConstTpl(tmpAddr.getAddressSpace()), new ConstTpl(ConstTpl.REAL,
new ConstTpl(ConstTpl.REAL, tmpAddr.getOffset()), UniqueLayout.RUNTIME_RETURN_LOCATION.getOffset(language)),
new ConstTpl(ConstTpl.REAL, ptrSize)); new ConstTpl(ConstTpl.REAL, ptrSize));
VarnodeTpl destAddr = new VarnodeTpl(new ConstTpl(const_space), inputs[0].getOffset(), VarnodeTpl destAddr = new VarnodeTpl(new ConstTpl(const_space), inputs[0].getOffset(),
@ -478,8 +477,37 @@ public abstract class PcodeEmit {
return hand.space; return hand.space;
} }
/**
* Adjust the dynamic pointer to account for a V_OFFSET_PLUS in the given VarnodeTpl.
* We are passed in an existing array (dyncache) of VarnodeData for input/output.
* We assume the location of the base pointer is in dyncache[1]
* @param dyncache is the existing array
* @param vn is the V_OFFSET_PLUS VarnodeTpl to adjust for
*/
private void generatePointerAdd(VarnodeData[] dyncache, VarnodeTpl vn) {
long offsetPlus = vn.getOffset().getReal() & 0xffff;
if (offsetPlus == 0) {
return;
}
VarnodeData tmpData = dyncache[0]; // Swap dyncache[1] with dyncache[0]
dyncache[0] = dyncache[1];
dyncache[1] = tmpData;
dyncache[1].space = const_space; // Put V_OFFSET_PLUS constant in dyncache[1]
dyncache[1].offset = offsetPlus;
dyncache[1].size = dyncache[0].size;
dyncache[2].space = uniq_space; // Result of INT_ADD in special runtime temp
dyncache[2].offset = UniqueLayout.RUNTIME_BITRANGE_EA.getOffset(language);
dyncache[2].size = dyncache[0].size;
dump(startAddress, PcodeOp.INT_ADD, dyncache, 2, dyncache[2]);
numOps += 1;
tmpData = dyncache[2];
dyncache[2] = dyncache[1];
dyncache[1] = tmpData;
}
private void dump(OpTpl opt) { private void dump(OpTpl opt) {
VarnodeData[] dyncache = null;
VarnodeTpl vn, outvn; VarnodeTpl vn, outvn;
int isize = opt.getInput().length; int isize = opt.getInput().length;
@ -493,13 +521,16 @@ public abstract class PcodeEmit {
dyncache[1] = new VarnodeData(); dyncache[1] = new VarnodeData();
dyncache[2] = new VarnodeData(); dyncache[2] = new VarnodeData();
generateLocation(vn, incache[i]); // Temporary storage generateLocation(vn, incache[i]); // Temporary storage
dyncache[2].space = incache[i].space;
dyncache[2].offset = incache[i].offset;
dyncache[2].size = incache[i].size;
AddressSpace spc = generatePointer(vn, dyncache[1]); AddressSpace spc = generatePointer(vn, dyncache[1]);
if (vn.getOffset().getSelect() == ConstTpl.V_OFFSET_PLUS) {
generatePointerAdd(dyncache, vn);
}
dyncache[0].space = const_space; dyncache[0].space = const_space;
dyncache[0].offset = spc.getSpaceID(); dyncache[0].offset = spc.getSpaceID();
dyncache[0].size = 4; // Size of spaceid dyncache[0].size = 4; // Size of spaceid
dyncache[2].space = incache[i].space;
dyncache[2].offset = incache[i].offset;
dyncache[2].size = incache[i].size;
dump(startAddress, PcodeOp.LOAD, dyncache, 2, dyncache[2]); dump(startAddress, PcodeOp.LOAD, dyncache, 2, dyncache[2]);
numOps += 1; numOps += 1;
} }
@ -524,13 +555,16 @@ public abstract class PcodeEmit {
generateLocation(outvn, outcache); // Temporary storage generateLocation(outvn, outcache); // Temporary storage
dump(startAddress, opt.getOpcode(), incache, isize, outcache); dump(startAddress, opt.getOpcode(), incache, isize, outcache);
numOps += 1; numOps += 1;
dyncache[2].space = outcache.space;
dyncache[2].offset = outcache.offset;
dyncache[2].size = outcache.size;
AddressSpace spc = generatePointer(outvn, dyncache[1]); AddressSpace spc = generatePointer(outvn, dyncache[1]);
if (outvn.getOffset().getSelect() == ConstTpl.V_OFFSET_PLUS) {
generatePointerAdd(dyncache, outvn);
}
dyncache[0].space = const_space; dyncache[0].space = const_space;
dyncache[0].offset = spc.getSpaceID(); dyncache[0].offset = spc.getSpaceID();
dyncache[0].size = 4; // Size of spaceid; dyncache[0].size = 4; // Size of spaceid;
dyncache[2].space = outcache.space;
dyncache[2].offset = outcache.offset;
dyncache[2].size = outcache.size;
dump(startAddress, PcodeOp.STORE, dyncache, 3, null); dump(startAddress, PcodeOp.STORE, dyncache, 3, null);
numOps += 1; numOps += 1;
} }
@ -576,8 +610,8 @@ public abstract class PcodeEmit {
/** /**
* Insert the p-code of instruction(s) in the delay slot at this point in the p-code generation for the current instruction * Insert the p-code of instruction(s) in the delay slot at this point in the p-code generation for the current instruction
* @param op is the DELAYSLOT directive * @param op is the DELAYSLOT directive
* @throws UnknownInstructionException * @throws UnknownInstructionException for problems finding the delay slot Instruction
* @throws MemoryAccessException * @throws MemoryAccessException for problems resolving details of the delay slot Instruction
*/ */
private void delaySlot(OpTpl op) throws UnknownInstructionException, MemoryAccessException { private void delaySlot(OpTpl op) throws UnknownInstructionException, MemoryAccessException {
@ -620,8 +654,8 @@ public abstract class PcodeEmit {
* Inject the p-code for a different instruction at this point in the p-code generation for current instruction * Inject the p-code for a different instruction at this point in the p-code generation for current instruction
* @param bld is the CROSSBUILD directive containing the section number and address parameters * @param bld is the CROSSBUILD directive containing the section number and address parameters
* @param secnum is the section number of the section containing the CROSSBUILD directive * @param secnum is the section number of the section containing the CROSSBUILD directive
* @throws UnknownInstructionException * @throws UnknownInstructionException for problems finding the referenced Instruction
* @throws MemoryAccessException * @throws MemoryAccessException for problems resolving details of the referenced Instruction
*/ */
private void appendCrossBuild(OpTpl bld, int secnum) private void appendCrossBuild(OpTpl bld, int secnum)
throws UnknownInstructionException, MemoryAccessException { throws UnknownInstructionException, MemoryAccessException {
@ -703,8 +737,8 @@ public abstract class PcodeEmit {
* Build a named p-code section of a constructor that contains only implied BUILD directives * Build a named p-code section of a constructor that contains only implied BUILD directives
* @param ct Constructor to build section for * @param ct Constructor to build section for
* @param secnum index of the section to be built * @param secnum index of the section to be built
* @throws MemoryAccessException * @throws MemoryAccessException for problems resolving details of the underlying Instruction
* @throws UnknownInstructionException * @throws UnknownInstructionException for problems finding the underlying Instruction
*/ */
private void buildEmpty(Constructor ct, int secnum) private void buildEmpty(Constructor ct, int secnum)
throws UnknownInstructionException, MemoryAccessException { throws UnknownInstructionException, MemoryAccessException {
@ -730,12 +764,9 @@ public abstract class PcodeEmit {
void checkOverlays(int opcode, VarnodeData[] in, int isize, VarnodeData out) { void checkOverlays(int opcode, VarnodeData[] in, int isize, VarnodeData out) {
if (overlayspace != null) { if (overlayspace != null) {
if (uniqueFactory == null) {
return;
}
if ((opcode == PcodeOp.LOAD) || (opcode == PcodeOp.STORE)) { if ((opcode == PcodeOp.LOAD) || (opcode == PcodeOp.STORE)) {
int spaceId = (int) in[0].offset; int spaceId = (int) in[0].offset;
AddressSpace space = uniqueFactory.getAddressFactory().getAddressSpace(spaceId); AddressSpace space = addressFactory.getAddressSpace(spaceId);
if (space.isOverlaySpace()) { if (space.isOverlaySpace()) {
space = ((OverlayAddressSpace) space).getOverlayedSpace(); space = ((OverlayAddressSpace) space).getOverlayedSpace();
in[0].offset = space.getSpaceID(); in[0].offset = space.getSpaceID();

View file

@ -17,7 +17,8 @@ package ghidra.app.plugin.processors.sleigh;
import java.util.ArrayList; import java.util.ArrayList;
import ghidra.program.model.address.*; import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSpace;
import ghidra.program.model.lang.InstructionContext; import ghidra.program.model.lang.InstructionContext;
import ghidra.program.model.pcode.*; import ghidra.program.model.pcode.*;
@ -32,7 +33,7 @@ public class PcodeEmitObjects extends PcodeEmit {
* @param walk state of the ParserContext from which to generate p-code * @param walk state of the ParserContext from which to generate p-code
*/ */
public PcodeEmitObjects(ParserWalker walk) { // For use with emitting precompiled p-code templates public PcodeEmitObjects(ParserWalker walk) { // For use with emitting precompiled p-code templates
this(walk, null, 0, null, null); this(walk, null, 0, null);
} }
/** /**
@ -42,7 +43,7 @@ public class PcodeEmitObjects extends PcodeEmit {
* of instruction including delay-sloted instructions) * of instruction including delay-sloted instructions)
*/ */
public PcodeEmitObjects(ParserWalker walk, int fallOffset) { // For use with emitting precompiled p-code templates public PcodeEmitObjects(ParserWalker walk, int fallOffset) { // For use with emitting precompiled p-code templates
this(walk, null, fallOffset, null, null); this(walk, null, fallOffset, null);
} }
/** /**
@ -50,12 +51,11 @@ public class PcodeEmitObjects extends PcodeEmit {
* @param ictx is the InstructionContext used to resolve delayslot and crossbuild directives * @param ictx is the InstructionContext used to resolve delayslot and crossbuild directives
* @param fallOffset default instruction fall offset (i.e., instruction length including delay slotted instructions) * @param fallOffset default instruction fall offset (i.e., instruction length including delay slotted instructions)
* @param override required if pcode overrides are to be utilized * @param override required if pcode overrides are to be utilized
* @param uniqueFactory required when override specified or if overlay normalization is required
*/ */
public PcodeEmitObjects(ParserWalker walk, InstructionContext ictx, int fallOffset, public PcodeEmitObjects(ParserWalker walk, InstructionContext ictx, int fallOffset,
PcodeOverride override, UniqueAddressFactory uniqueFactory) { PcodeOverride override) {
super(walk, ictx, fallOffset, override, uniqueFactory); super(walk, ictx, fallOffset, override);
oplist = new ArrayList<PcodeOp>(); oplist = new ArrayList<>();
} }
public PcodeOp[] getPcodeOp() { public PcodeOp[] getPcodeOp() {
@ -72,8 +72,7 @@ public class PcodeEmitObjects extends PcodeEmit {
if (labelref == null) { if (labelref == null) {
return; return;
} }
for (int i = 0; i < labelref.size(); ++i) { for (Integer opindex : labelref) {
int opindex = labelref.get(i);
PcodeOp op = oplist.get(opindex); PcodeOp op = oplist.get(opindex);
Varnode vn = op.getInput(0); Varnode vn = op.getInput(0);
int labelid = (int) vn.getOffset(); int labelid = (int) vn.getOffset();
@ -98,7 +97,7 @@ public class PcodeEmitObjects extends PcodeEmit {
@Override @Override
void addLabelRef() { void addLabelRef() {
if (labelref == null) { if (labelref == null) {
labelref = new ArrayList<Integer>(); labelref = new ArrayList<>();
} }
labelref.add(numOps); labelref.add(numOps);
} }

View file

@ -17,7 +17,8 @@ package ghidra.app.plugin.processors.sleigh;
import java.util.ArrayList; import java.util.ArrayList;
import ghidra.program.model.address.*; import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSpace;
import ghidra.program.model.lang.InstructionContext; import ghidra.program.model.lang.InstructionContext;
import ghidra.program.model.lang.PackedBytes; import ghidra.program.model.lang.PackedBytes;
import ghidra.program.model.pcode.PcodeOp; import ghidra.program.model.pcode.PcodeOp;
@ -63,11 +64,10 @@ public class PcodeEmitPacked extends PcodeEmit {
* @param ictx instruction contexts * @param ictx instruction contexts
* @param fallOffset default instruction fall offset (i.e., instruction length including delay slotted instructions) * @param fallOffset default instruction fall offset (i.e., instruction length including delay slotted instructions)
* @param override required if pcode overrides are to be utilized * @param override required if pcode overrides are to be utilized
* @param uniqueFactory required when override specified or if overlay normalization is required
*/ */
public PcodeEmitPacked(ParserWalker walk, InstructionContext ictx, int fallOffset, public PcodeEmitPacked(ParserWalker walk, InstructionContext ictx, int fallOffset,
PcodeOverride override, UniqueAddressFactory uniqueFactory) { PcodeOverride override) {
super(walk, ictx, fallOffset, override, uniqueFactory); super(walk, ictx, fallOffset, override);
buf = new PackedBytes(512); buf = new PackedBytes(512);
} }
@ -80,8 +80,7 @@ public class PcodeEmitPacked extends PcodeEmit {
if (labelref == null) { if (labelref == null) {
return; return;
} }
for (int i = 0; i < labelref.size(); ++i) { for (LabelRef ref : labelref) {
LabelRef ref = labelref.get(i);
if ((ref.labelIndex >= labeldef.size()) || (labeldef.get(ref.labelIndex) == null)) { if ((ref.labelIndex >= labeldef.size()) || (labeldef.get(ref.labelIndex) == null)) {
throw new SleighException("Reference to non-existant sleigh label"); throw new SleighException("Reference to non-existant sleigh label");
} }
@ -102,7 +101,7 @@ public class PcodeEmitPacked extends PcodeEmit {
@Override @Override
void addLabelRef() { void addLabelRef() {
if (labelref == null) { if (labelref == null) {
labelref = new ArrayList<LabelRef>(); labelref = new ArrayList<>();
} }
int labelIndex = (int) incache[0].offset; int labelIndex = (int) incache[0].offset;
int labelSize = incache[0].size; int labelSize = incache[0].size;

View file

@ -161,19 +161,22 @@ public class SleighInstructionPrototype implements InstructionPrototype {
private static void addExplicitFlow(ConstructState state, OpTpl op, int flags, private static void addExplicitFlow(ConstructState state, OpTpl op, int flags,
FlowSummary summary) { FlowSummary summary) {
if (summary.flowState == null) if (summary.flowState == null) {
summary.flowState = new ArrayList<>(); summary.flowState = new ArrayList<>();
}
FlowRecord res = new FlowRecord(); FlowRecord res = new FlowRecord();
summary.flowState.add(res); summary.flowState.add(res);
res.flowFlags = flags; res.flowFlags = flags;
res.op = op; res.op = op;
res.addressnode = null; res.addressnode = null;
VarnodeTpl dest = op.getInput()[0]; // First varnode input contains the destination address VarnodeTpl dest = op.getInput()[0]; // First varnode input contains the destination address
if ((flags & (JUMPOUT | CALL | CROSSBUILD)) == 0) if ((flags & (JUMPOUT | CALL | CROSSBUILD)) == 0) {
return; return;
}
// If the flow is out of the instruction, store the ConstructState so we can easily calculate address // If the flow is out of the instruction, store the ConstructState so we can easily calculate address
if (state == null) if (state == null) {
return; return;
}
if ((flags & CROSSBUILD) != 0) { if ((flags & CROSSBUILD) != 0) {
res.addressnode = state; res.addressnode = state;
} }
@ -218,24 +221,31 @@ public class SleighInstructionPrototype implements InstructionPrototype {
break; break;
case PcodeOp.BRANCH: case PcodeOp.BRANCH:
destType = res.lastop.getInput()[0].getOffset().getType(); destType = res.lastop.getInput()[0].getOffset().getType();
if (destType == ConstTpl.J_NEXT) if (destType == ConstTpl.J_NEXT) {
flags = BRANCH_TO_END; flags = BRANCH_TO_END;
else if (destType == ConstTpl.J_START) }
else if (destType == ConstTpl.J_START) {
flags = NO_FALLTHRU; flags = NO_FALLTHRU;
else if (destType == ConstTpl.J_RELATIVE) }
else if (destType == ConstTpl.J_RELATIVE) {
flags = NO_FALLTHRU; flags = NO_FALLTHRU;
else }
else {
flags = JUMPOUT | NO_FALLTHRU; flags = JUMPOUT | NO_FALLTHRU;
}
addExplicitFlow(walker.getState(), res.lastop, flags, res); addExplicitFlow(walker.getState(), res.lastop, flags, res);
break; break;
case PcodeOp.CBRANCH: case PcodeOp.CBRANCH:
destType = res.lastop.getInput()[0].getOffset().getType(); destType = res.lastop.getInput()[0].getOffset().getType();
if (destType == ConstTpl.J_NEXT) if (destType == ConstTpl.J_NEXT) {
flags = BRANCH_TO_END; flags = BRANCH_TO_END;
else if ((destType != ConstTpl.J_START) && (destType != ConstTpl.J_RELATIVE)) }
else if ((destType != ConstTpl.J_START) && (destType != ConstTpl.J_RELATIVE)) {
flags = JUMPOUT; flags = JUMPOUT;
else }
else {
flags = 0; flags = 0;
}
addExplicitFlow(walker.getState(), res.lastop, flags, res); addExplicitFlow(walker.getState(), res.lastop, flags, res);
break; break;
case PcodeOp.CALL: case PcodeOp.CALL:
@ -252,8 +262,9 @@ public class SleighInstructionPrototype implements InstructionPrototype {
break; break;
case PcodeOp.INDIRECT: // Encode delayslot case PcodeOp.INDIRECT: // Encode delayslot
destType = (int) res.lastop.getInput()[0].getOffset().getReal(); destType = (int) res.lastop.getInput()[0].getOffset().getReal();
if (destType > res.delay) if (destType > res.delay) {
res.delay = destType; res.delay = destType;
}
default: default:
break; break;
@ -263,8 +274,9 @@ public class SleighInstructionPrototype implements InstructionPrototype {
} }
public static FlowType flowListToFlowType(List<FlowRecord> flowstate) { public static FlowType flowListToFlowType(List<FlowRecord> flowstate) {
if (flowstate == null) if (flowstate == null) {
return RefType.FALL_THROUGH; return RefType.FALL_THROUGH;
}
int flags = 0; int flags = 0;
for (FlowRecord rec : flowstate) { for (FlowRecord rec : flowstate) {
flags &= ~(NO_FALLTHRU | CROSSBUILD | LABEL); flags &= ~(NO_FALLTHRU | CROSSBUILD | LABEL);
@ -307,8 +319,9 @@ public class SleighInstructionPrototype implements InstructionPrototype {
private static FlowType convertFlowFlags(int flowFlags) { private static FlowType convertFlowFlags(int flowFlags) {
if ((flowFlags & LABEL) != 0) if ((flowFlags & LABEL) != 0) {
flowFlags |= BRANCH_TO_END; flowFlags |= BRANCH_TO_END;
}
flowFlags &= ~(CROSSBUILD | LABEL); flowFlags &= ~(CROSSBUILD | LABEL);
// NOTE: If prototype has cross-build, flow must be determined dynamically // NOTE: If prototype has cross-build, flow must be determined dynamically
switch (flowFlags) { // Convert flags to a standard flowtype switch (flowFlags) { // Convert flags to a standard flowtype
@ -395,8 +408,9 @@ public class SleighInstructionPrototype implements InstructionPrototype {
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (obj == null) if (obj == null) {
return false; return false;
}
return (hashCode() == obj.hashCode()); // Trust entirely in hash return (hashCode() == obj.hashCode()); // Trust entirely in hash
} }
@ -415,8 +429,9 @@ public class SleighInstructionPrototype implements InstructionPrototype {
@Override @Override
public FlowType getFlowType(InstructionContext context) { public FlowType getFlowType(InstructionContext context) {
if (!hasCrossBuilds) if (!hasCrossBuilds) {
return flowType; return flowType;
}
int flags = 0; int flags = 0;
try { try {
flags = gatherFlags(0, context, -1); flags = gatherFlags(0, context, -1);
@ -473,8 +488,9 @@ public class SleighInstructionPrototype implements InstructionPrototype {
@Override @Override
public int getOpType(int opIndex, InstructionContext context) { public int getOpType(int opIndex, InstructionContext context) {
if (opIndex < 0 || opIndex >= opresolve.length) if (opIndex < 0 || opIndex >= opresolve.length) {
return OperandType.DYNAMIC; return OperandType.DYNAMIC;
}
SleighParserContext protoContext; SleighParserContext protoContext;
try { try {
@ -485,21 +501,26 @@ public class SleighInstructionPrototype implements InstructionPrototype {
} }
ConstructState opState = mnemonicState.getSubState(opresolve[opIndex]); ConstructState opState = mnemonicState.getSubState(opresolve[opIndex]);
FixedHandle hand = protoContext.getFixedHandle(opState); FixedHandle hand = protoContext.getFixedHandle(opState);
if (hand.isInvalid()) if (hand.isInvalid()) {
return OperandType.DYNAMIC; return OperandType.DYNAMIC;
}
int indirect = isIndirect(opresolve[opIndex]) ? OperandType.INDIRECT : 0; int indirect = isIndirect(opresolve[opIndex]) ? OperandType.INDIRECT : 0;
if (hand.offset_space == null) { // Static handle if (hand.offset_space == null) { // Static handle
int type = hand.space.getType(); int type = hand.space.getType();
if (type == AddressSpace.TYPE_REGISTER) if (type == AddressSpace.TYPE_REGISTER) {
return OperandType.REGISTER | indirect; return OperandType.REGISTER | indirect;
if (type == AddressSpace.TYPE_CONSTANT) }
if (type == AddressSpace.TYPE_CONSTANT) {
return OperandType.SCALAR | indirect; return OperandType.SCALAR | indirect;
}
OperandSymbol sym = mnemonicState.getConstructor().getOperand(opresolve[opIndex]); OperandSymbol sym = mnemonicState.getConstructor().getOperand(opresolve[opIndex]);
if (sym.isCodeAddress()) if (sym.isCodeAddress()) {
return (OperandType.ADDRESS | OperandType.CODE | indirect); return (OperandType.ADDRESS | OperandType.CODE | indirect);
if (type == AddressSpace.TYPE_RAM) }
if (type == AddressSpace.TYPE_RAM) {
return (OperandType.ADDRESS | OperandType.DATA | indirect); return (OperandType.ADDRESS | OperandType.DATA | indirect);
} }
}
return OperandType.DYNAMIC | indirect; return OperandType.DYNAMIC | indirect;
} }
@ -565,13 +586,16 @@ public class SleighInstructionPrototype implements InstructionPrototype {
private int gatherFlags(int curflags, InstructionContext context, int secnum) private int gatherFlags(int curflags, InstructionContext context, int secnum)
throws MemoryAccessException, UnknownContextException { throws MemoryAccessException, UnknownContextException {
List<FlowRecord> curlist = null; List<FlowRecord> curlist = null;
if (secnum < 0) if (secnum < 0) {
curlist = flowStateList; curlist = flowStateList;
else if ((flowStateListNamed != null) && (secnum < flowStateListNamed.size())) }
else if ((flowStateListNamed != null) && (secnum < flowStateListNamed.size())) {
curlist = flowStateListNamed.get(secnum); curlist = flowStateListNamed.get(secnum);
}
if (curlist == null) if (curlist == null) {
return curflags; return curflags;
}
for (FlowRecord rec : curlist) { for (FlowRecord rec : curlist) {
if ((rec.flowFlags & CROSSBUILD) != 0) { if ((rec.flowFlags & CROSSBUILD) != 0) {
@ -618,13 +642,16 @@ public class SleighInstructionPrototype implements InstructionPrototype {
InstructionContext context, int secnum) InstructionContext context, int secnum)
throws MemoryAccessException, UnknownContextException { throws MemoryAccessException, UnknownContextException {
List<FlowRecord> curlist = null; List<FlowRecord> curlist = null;
if (secnum < 0) if (secnum < 0) {
curlist = flowStateList; curlist = flowStateList;
else if ((flowStateListNamed != null) && (secnum < flowStateListNamed.size())) }
else if ((flowStateListNamed != null) && (secnum < flowStateListNamed.size())) {
curlist = flowStateListNamed.get(secnum); curlist = flowStateListNamed.get(secnum);
}
if (curlist == null) if (curlist == null) {
return; return;
}
for (FlowRecord rec : curlist) { for (FlowRecord rec : curlist) {
if ((rec.flowFlags & CROSSBUILD) != 0) { if ((rec.flowFlags & CROSSBUILD) != 0) {
@ -654,8 +681,9 @@ public class SleighInstructionPrototype implements InstructionPrototype {
@Override @Override
public Address[] getFlows(InstructionContext context) { public Address[] getFlows(InstructionContext context) {
if (flowStateList.size() == 0) if (flowStateList.size() == 0) {
return emptyFlow; return emptyFlow;
}
ArrayList<Address> addresses = new ArrayList<>(); ArrayList<Address> addresses = new ArrayList<>();
try { try {
@ -668,8 +696,9 @@ public class SleighInstructionPrototype implements InstructionPrototype {
return emptyFlow; return emptyFlow;
} }
if (addresses.size() == 0) if (addresses.size() == 0) {
return emptyFlow; return emptyFlow;
}
return addresses.toArray(new Address[addresses.size()]); return addresses.toArray(new Address[addresses.size()]);
} }
@ -746,9 +775,10 @@ public class SleighInstructionPrototype implements InstructionPrototype {
protoContext = (SleighParserContext) context.getParserContext(); protoContext = (SleighParserContext) context.getParserContext();
ConstructState opState = mnemonicState.getSubState(opresolve[opIndex]); ConstructState opState = mnemonicState.getSubState(opresolve[opIndex]);
hand = protoContext.getFixedHandle(opState); hand = protoContext.getFixedHandle(opState);
if (hand.isInvalid()) if (hand.isInvalid()) {
return null; return null;
} }
}
catch (Exception e) { catch (Exception e) {
return null; return null;
} }
@ -769,8 +799,9 @@ public class SleighInstructionPrototype implements InstructionPrototype {
ConstructState opState = mnemonicState.getSubState(opresolve[opIndex]); ConstructState opState = mnemonicState.getSubState(opresolve[opIndex]);
FixedHandle hand = protoContext.getFixedHandle(opState); FixedHandle hand = protoContext.getFixedHandle(opState);
if (hand.isInvalid()) if (hand.isInvalid()) {
return null; return null;
}
if (hand.space.getType() == AddressSpace.TYPE_CONSTANT) { if (hand.space.getType() == AddressSpace.TYPE_CONSTANT) {
int size = hand.size; int size = hand.size;
if (size == 0) { if (size == 0) {
@ -798,8 +829,9 @@ public class SleighInstructionPrototype implements InstructionPrototype {
SleighParserContext protoContext = (SleighParserContext) context.getParserContext(); SleighParserContext protoContext = (SleighParserContext) context.getParserContext();
ConstructState opState = mnemonicState.getSubState(opresolve[opIndex]); ConstructState opState = mnemonicState.getSubState(opresolve[opIndex]);
FixedHandle hand = protoContext.getFixedHandle(opState); FixedHandle hand = protoContext.getFixedHandle(opState);
if (hand.isInvalid()) if (hand.isInvalid()) {
return null; return null;
}
if (hand.space.getType() == AddressSpace.TYPE_REGISTER) { if (hand.space.getType() == AddressSpace.TYPE_REGISTER) {
return language.getRegister(hand.space, hand.offset_offset, hand.size); return language.getRegister(hand.space, hand.offset_offset, hand.size);
} }
@ -834,7 +866,7 @@ public class SleighInstructionPrototype implements InstructionPrototype {
public Object[] getInputObjects(InstructionContext context) { public Object[] getInputObjects(InstructionContext context) {
PcodeOp[] pcode = null; PcodeOp[] pcode = null;
try { try {
pcode = getPcode(context, null, null); pcode = getPcode(context, null);
} }
catch (Exception e) { catch (Exception e) {
return new Object[0]; return new Object[0];
@ -892,7 +924,7 @@ public class SleighInstructionPrototype implements InstructionPrototype {
public Object[] getResultObjects(InstructionContext context) { public Object[] getResultObjects(InstructionContext context) {
PcodeOp[] pcode = null; PcodeOp[] pcode = null;
try { try {
pcode = getPcode(context, null, null); pcode = getPcode(context, null);
} }
catch (Exception e) { catch (Exception e) {
return new Object[0]; return new Object[0];
@ -944,8 +976,7 @@ public class SleighInstructionPrototype implements InstructionPrototype {
} }
@Override @Override
public PcodeOp[] getPcode(InstructionContext context, PcodeOverride override, public PcodeOp[] getPcode(InstructionContext context, PcodeOverride override) {
UniqueAddressFactory uniqueFactory) {
try { try {
SleighParserContext protoContext = (SleighParserContext) context.getParserContext(); SleighParserContext protoContext = (SleighParserContext) context.getParserContext();
int fallOffset = getLength(); int fallOffset = getLength();
@ -964,8 +995,7 @@ public class SleighInstructionPrototype implements InstructionPrototype {
} }
ParserWalker walker = new ParserWalker(protoContext); ParserWalker walker = new ParserWalker(protoContext);
walker.baseState(); walker.baseState();
PcodeEmitObjects emit = PcodeEmitObjects emit = new PcodeEmitObjects(walker, context, fallOffset, override);
new PcodeEmitObjects(walker, context, fallOffset, override, uniqueFactory);
emit.build(walker.getConstructor().getTempl(), -1); emit.build(walker.getConstructor().getTempl(), -1);
emit.resolveRelatives(); emit.resolveRelatives();
if (!isindelayslot) { if (!isindelayslot) {
@ -986,8 +1016,7 @@ public class SleighInstructionPrototype implements InstructionPrototype {
} }
@Override @Override
public PackedBytes getPcodePacked(InstructionContext context, PcodeOverride override, public PackedBytes getPcodePacked(InstructionContext context, PcodeOverride override) {
UniqueAddressFactory uniqueFactory) {
int fallOffset = getLength(); int fallOffset = getLength();
try { try {
SleighParserContext protoContext = (SleighParserContext) context.getParserContext(); SleighParserContext protoContext = (SleighParserContext) context.getParserContext();
@ -1006,8 +1035,7 @@ public class SleighInstructionPrototype implements InstructionPrototype {
} }
ParserWalker walker = new ParserWalker(protoContext); ParserWalker walker = new ParserWalker(protoContext);
walker.baseState(); walker.baseState();
PcodeEmitPacked emit = PcodeEmitPacked emit = new PcodeEmitPacked(walker, context, fallOffset, override);
new PcodeEmitPacked(walker, context, fallOffset, override, uniqueFactory);
emit.write(PcodeEmitPacked.inst_tag); emit.write(PcodeEmitPacked.inst_tag);
emit.dumpOffset(emit.getFallOffset()); emit.dumpOffset(emit.getFallOffset());
@ -1067,7 +1095,7 @@ public class SleighInstructionPrototype implements InstructionPrototype {
@Override @Override
public RefType getOperandRefType(int opIndex, InstructionContext context, public RefType getOperandRefType(int opIndex, InstructionContext context,
PcodeOverride override, UniqueAddressFactory uniqueFactory) { PcodeOverride override) {
if (opIndex < 0 || opIndex >= opRefTypes.length) { if (opIndex < 0 || opIndex >= opRefTypes.length) {
return null; return null;
} }
@ -1085,7 +1113,7 @@ public class SleighInstructionPrototype implements InstructionPrototype {
if (refType != null) { if (refType != null) {
return refType; return refType;
} }
cacheDefaultOperandRefTypes(context, uniqueFactory); cacheDefaultOperandRefTypes(context);
return opRefTypes[opIndex]; return opRefTypes[opIndex];
} }
@ -1097,7 +1125,7 @@ public class SleighInstructionPrototype implements InstructionPrototype {
catch (MemoryAccessException e) { catch (MemoryAccessException e) {
return RefType.DATA; return RefType.DATA;
} }
PcodeOp[] pcode = getPcode(context, override, uniqueFactory); PcodeOp[] pcode = getPcode(context, override);
if (pcode == null || pcode.length == 0) { if (pcode == null || pcode.length == 0) {
return RefType.DATA; return RefType.DATA;
} }
@ -1121,8 +1149,7 @@ public class SleighInstructionPrototype implements InstructionPrototype {
return refType; return refType;
} }
private void cacheDefaultOperandRefTypes(InstructionContext context, private void cacheDefaultOperandRefTypes(InstructionContext context) {
UniqueAddressFactory uniqueFactory) {
// Resolve handles for each operand // Resolve handles for each operand
SleighParserContext protoContext; SleighParserContext protoContext;
@ -1132,7 +1159,7 @@ public class SleighInstructionPrototype implements InstructionPrototype {
catch (MemoryAccessException e) { catch (MemoryAccessException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
PcodeOp[] pcode = getPcode(context, null, uniqueFactory); PcodeOp[] pcode = getPcode(context, null);
if (pcode == null || pcode.length == 0) { if (pcode == null || pcode.length == 0) {
return; return;
} }
@ -1342,8 +1369,9 @@ public class SleighInstructionPrototype implements InstructionPrototype {
if (subct != null) { if (subct != null) {
walker.setConstructor(subct); walker.setConstructor(subct);
subct.applyContext(walker, debug); subct.applyContext(walker, debug);
if (debug != null) if (debug != null) {
debug.indent(); debug.indent();
}
break; break;
} }
if (debug != null) { if (debug != null) {
@ -1355,9 +1383,10 @@ public class SleighInstructionPrototype implements InstructionPrototype {
} }
} }
else { else {
if (debug != null) if (debug != null) {
debug.dumpPattern(sym, walker); debug.dumpPattern(sym, walker);
} }
}
walker.setCurrentLength(sym.getMinimumLength()); walker.setCurrentLength(sym.getMinimumLength());
walker.popOperand(); walker.popOperand();
oper += 1; oper += 1;
@ -1416,11 +1445,13 @@ public class SleighInstructionPrototype implements InstructionPrototype {
ConstructTpl templ = ct.getTempl(); ConstructTpl templ = ct.getTempl();
if (templ != null) { if (templ != null) {
HandleTpl res = templ.getResult(); HandleTpl res = templ.getResult();
if (res != null) // Pop up handle to containing operand if (res != null) { // Pop up handle to containing operand
res.fix(walker.getParentHandle(), walker); res.fix(walker.getParentHandle(), walker);
else }
else {
walker.getParentHandle().setInvalid(); walker.getParentHandle().setInvalid();
} }
}
walker.popOperand(); walker.popOperand();
} }
} }
@ -1442,8 +1473,9 @@ public class SleighInstructionPrototype implements InstructionPrototype {
if (ct != null) { if (ct != null) {
int oper = walker.getOperand(); int oper = walker.getOperand();
int numoper = ct.getNumOperands(); int numoper = ct.getNumOperands();
if (oper == 0) // Upon first entry to this Constructor if (oper == 0) { // Upon first entry to this Constructor
ct.applyContext(walker, debug); // Apply its context changes ct.applyContext(walker, debug); // Apply its context changes
}
if (oper < numoper) { if (oper < numoper) {
walker.pushOperand(oper); walker.pushOperand(oper);
continue; continue;

View file

@ -904,8 +904,8 @@ public class SleighLanguage implements Language {
Endian ldefEndian = description.getEndian(); Endian ldefEndian = description.getEndian();
Endian instEndian = description.getInstructionEndian(); Endian instEndian = description.getInstructionEndian();
if (slaEndian != ldefEndian && instEndian == ldefEndian) { if (slaEndian != ldefEndian && instEndian == ldefEndian) {
throw new SleighException(".ldefs says " + getLanguageID() + " is " + throw new SleighException(".ldefs says " + getLanguageID() + " is " + ldefEndian +
ldefEndian + " but .sla says " + slaEndian); " but .sla says " + slaEndian);
} }
uniqueBase = SpecXmlUtils.decodeLong(el.getAttribute("uniqbase")); uniqueBase = SpecXmlUtils.decodeLong(el.getAttribute("uniqbase"));
alignment = SpecXmlUtils.decodeInt(el.getAttribute("align")); alignment = SpecXmlUtils.decodeInt(el.getAttribute("align"));
@ -935,9 +935,9 @@ public class SleighLanguage implements Language {
String defname = el.getAttribute("defaultspace"); String defname = el.getAttribute("defaultspace");
spacetable = new LinkedHashMap<>(); spacetable = new LinkedHashMap<>();
// Slot zero is always the constant space // Slot zero is always the constant space
AddressSpace constspc = new GenericAddressSpace("const", 64, AddressSpace.TYPE_CONSTANT, 0); AddressSpace constspc = new GenericAddressSpace(SpaceNames.CONSTANT_SPACE_NAME, 64,
spacetable.put("const", constspc); AddressSpace.TYPE_CONSTANT, SpaceNames.CONSTANT_SPACE_INDEX);
//spacetable.put("OTHER", AddressSpace.OTHER_SPACE); spacetable.put(SpaceNames.CONSTANT_SPACE_NAME, constspc);
default_space = null; default_space = null;
XmlElement subel = parser.peek(); XmlElement subel = parser.peek();
if (subel.getName().equals("space_other")) { // tag must be present if (subel.getName().equals("space_other")) { // tag must be present

View file

@ -0,0 +1,58 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.plugin.processors.sleigh;
/**
* Offsets for various ranges in the p-code unique space. Offsets are either:
* 1) Relative to the last temporary allocated statically by the SLEIGH compiler
* or a particular language (.sla), OR
* 2) Absolute within the unique address space.
* So the layout of the unique address space looks like:
* 1) SLEIGH static temporaries
* 2) Runtime temporaries used by the SLEIGH p-code generator
* 3) Temporaries used by the PcodeInjectLibrary for p-code snippets
* 4) Temporaries generated during (decompiler) analysis
*
* The "unique" space is set to 32 bits across all architectures.
* The maximum offset is 0xFFFFFFFF.
* The offsets and names should match with the parallel decompiler enum in translate.hh
*/
public enum UniqueLayout {
SLEIGH_BASE(0, true), // First offset after SLEIGH static temporaries
RUNTIME_BOOLEAN_INVERT(0, true),
RUNTIME_RETURN_LOCATION(0x80, true),
RUNTIME_BITRANGE_EA(0x100, true),
INJECT(0x200, true),
ANALYSIS(0x10000000, false);
private final long offset;
private final boolean isRelative; // Is this offset relative to the end of SLEIGH statics
UniqueLayout(long off, boolean isRel) {
offset = off;
isRelative = isRel;
}
/**
* Get the starting offset of a named range in the unique address space. The returned offset
* is absolute and specific to the given SLEIGH language.
* @param language is the given SLEIGH language
* @return the absolute offset
*/
public long getOffset(SleighLanguage language) {
return (isRelative && language != null) ? language.getUniqueBase() + offset : offset;
}
}

View file

@ -95,6 +95,14 @@ public class ConstTpl {
select = (short) vf; select = (short) vf;
} }
public ConstTpl(int tp, long val, AddressSpace spc, int ht, int sel) {
type = tp;
value_real = val;
value_spaceid = spc;
handle_index = (short) ht;
select = (short) sel;
}
public boolean isConstSpace() { public boolean isConstSpace() {
if (type == SPACEID) { if (type == SPACEID) {
return (value_spaceid.getType() == AddressSpace.TYPE_CONSTANT); return (value_spaceid.getType() == AddressSpace.TYPE_CONSTANT);
@ -121,6 +129,10 @@ public class ConstTpl {
return handle_index; return handle_index;
} }
public int getSelect() {
return select;
}
public int getType() { public int getType() {
return type; return type;
} }
@ -160,8 +172,7 @@ public class ConstTpl {
return hand.size; return hand.size;
case V_OFFSET_PLUS: case V_OFFSET_PLUS:
if (hand.space.getType() != AddressSpace.TYPE_CONSTANT) { // If we are not a constant if (hand.space.getType() != AddressSpace.TYPE_CONSTANT) { // If we are not a constant
if (hand.offset_space == null) if (hand.offset_space == null) {
{
return hand.offset_offset + (value_real & 0xffff); // Adjust offset by truncation amount return hand.offset_offset + (value_real & 0xffff); // Adjust offset by truncation amount
} }
return hand.temp_offset + (value_real & 0xffff); return hand.temp_offset + (value_real & 0xffff);

View file

@ -63,6 +63,19 @@ public class ConstructTpl {
result = null; result = null;
} }
/**
* Manually build a constructor template from pieces. This is used to translate from the
* internal SLEIGH compiler pcodeCPort.semantics.ConstructTpl
* @param opvec is the list of p-code op templates making up the constructor
* @param res is the result handle template for the constructor
* @param nmLabels is the number of labels int the template
*/
public ConstructTpl(OpTpl[] opvec, HandleTpl res, int nmLabels) {
vec = opvec;
result = res;
numlabels = nmLabels;
}
/** /**
* @return the number of labels needing resolution in this template * @return the number of labels needing resolution in this template
*/ */

View file

@ -45,6 +45,17 @@ public class HandleTpl {
protected HandleTpl() { protected HandleTpl() {
} }
public HandleTpl(ConstTpl spc, ConstTpl sz, ConstTpl ptrspc, ConstTpl ptroff, ConstTpl ptrsz,
ConstTpl tmpspc, ConstTpl tmpoff) {
space = spc;
size = sz;
ptrspace = ptrspc;
ptroffset = ptroff;
ptrsize = ptrsz;
temp_space = tmpspc;
temp_offset = tmpoff;
}
public void fix(FixedHandle hand, ParserWalker walker) { public void fix(FixedHandle hand, ParserWalker walker) {
if (ptrspace.getType() == ConstTpl.REAL) { if (ptrspace.getType() == ConstTpl.REAL) {
// The export is unstarred, but this doesn't mean // The export is unstarred, but this doesn't mean
@ -72,8 +83,9 @@ public class HandleTpl {
} }
public void fixPrintPiece(FixedHandle hand, ParserWalker walker, int handleIndex) { public void fixPrintPiece(FixedHandle hand, ParserWalker walker, int handleIndex) {
if (!hand.fixable) if (!hand.fixable) {
return; return;
}
if (hand.space.getType() != AddressSpace.TYPE_CONSTANT) { if (hand.space.getType() != AddressSpace.TYPE_CONSTANT) {
hand.fixable = false; hand.fixable = false;
return; return;

View file

@ -56,7 +56,7 @@ public class PseudoInstruction extends PseudoCodeUnit implements Instruction, In
/** /**
* Construct a new PseudoInstruction within a program. * Construct a new PseudoInstruction within a program.
* @param program * @param program is the given Program
* @param addr address of the instruction * @param addr address of the instruction
* @param prototype prototype of the instruction * @param prototype prototype of the instruction
* @param memBuffer buffer containing the bytes for the instruction * @param memBuffer buffer containing the bytes for the instruction
@ -221,22 +221,25 @@ public class PseudoInstruction extends PseudoCodeUnit implements Instruction, In
@Override @Override
public Scalar getScalar(int opIndex) { public Scalar getScalar(int opIndex) {
if (opIndex < 0) if (opIndex < 0) {
return null; return null;
}
return instrProto.getScalar(opIndex, this); return instrProto.getScalar(opIndex, this);
} }
@Override @Override
public Register getRegister(int opIndex) { public Register getRegister(int opIndex) {
if (opIndex < 0) if (opIndex < 0) {
return null; return null;
}
return instrProto.getRegister(opIndex, this); return instrProto.getRegister(opIndex, this);
} }
@Override @Override
public Object[] getOpObjects(int opIndex) { public Object[] getOpObjects(int opIndex) {
if (opIndex < 0) if (opIndex < 0) {
return new Object[0]; return new Object[0];
}
return instrProto.getOpObjects(opIndex, this); return instrProto.getOpObjects(opIndex, this);
} }
@ -393,16 +396,15 @@ public class PseudoInstruction extends PseudoCodeUnit implements Instruction, In
@Override @Override
public PcodeOp[] getPcode() { public PcodeOp[] getPcode() {
return instrProto.getPcode(this, null, null); return instrProto.getPcode(this, null);
} }
@Override @Override
public PcodeOp[] getPcode(boolean includeOverrides) { public PcodeOp[] getPcode(boolean includeOverrides) {
if (!includeOverrides || addrFactory == null) { if (!includeOverrides || addrFactory == null) {
return instrProto.getPcode(this, null, null); return instrProto.getPcode(this, null);
} }
return instrProto.getPcode(this, new InstructionPcodeOverride(this), return instrProto.getPcode(this, new InstructionPcodeOverride(this));
new UniqueAddressFactory(addrFactory, instrProto.getLanguage()));
} }
@Override @Override
@ -422,8 +424,9 @@ public class PseudoInstruction extends PseudoCodeUnit implements Instruction, In
@Override @Override
public Instruction getNext() { public Instruction getNext() {
if (program == null) if (program == null) {
return null; return null;
}
return program.getListing().getInstructionAfter(address); return program.getListing().getInstructionAfter(address);
} }
@ -444,8 +447,9 @@ public class PseudoInstruction extends PseudoCodeUnit implements Instruction, In
} }
} }
} }
if (program == null) if (program == null) {
return null; return null;
}
return program.getListing().getInstructionBefore(address); return program.getListing().getInstructionBefore(address);
} }

View file

@ -37,7 +37,7 @@ import ghidra.pcodeCPort.slghsymbol.*;
import ghidra.pcodeCPort.space.*; import ghidra.pcodeCPort.space.*;
import ghidra.pcodeCPort.utils.Utils; import ghidra.pcodeCPort.utils.Utils;
import ghidra.pcodeCPort.xml.DocumentStorage; import ghidra.pcodeCPort.xml.DocumentStorage;
import ghidra.program.model.lang.BasicCompilerSpec; import ghidra.program.model.lang.SpaceNames;
import ghidra.sleigh.grammar.*; import ghidra.sleigh.grammar.*;
import ghidra.util.Msg; import ghidra.util.Msg;
import utilities.util.FileResolutionResult; import utilities.util.FileResolutionResult;
@ -272,16 +272,16 @@ public class SleighCompile extends SleighBase {
// Some predefined symbols // Some predefined symbols
root = new SubtableSymbol(location, "instruction"); // Base constructors root = new SubtableSymbol(location, "instruction"); // Base constructors
symtab.addSymbol(root); symtab.addSymbol(root);
insertSpace(new ConstantSpace(this, "const", BasicCompilerSpec.CONSTANT_SPACE_INDEX)); insertSpace(new ConstantSpace(this));
SpaceSymbol spacesym = new SpaceSymbol(location, getConstantSpace()); // Constant SpaceSymbol spacesym = new SpaceSymbol(location, getConstantSpace()); // Constant
// space // space
symtab.addSymbol(spacesym); symtab.addSymbol(spacesym);
OtherSpace otherSpace = new OtherSpace(this, BasicCompilerSpec.OTHER_SPACE_NAME, OtherSpace otherSpace =
BasicCompilerSpec.OTHER_SPACE_INDEX); new OtherSpace(this, SpaceNames.OTHER_SPACE_NAME, SpaceNames.OTHER_SPACE_INDEX);
insertSpace(otherSpace); insertSpace(otherSpace);
spacesym = new SpaceSymbol(location, otherSpace); spacesym = new SpaceSymbol(location, otherSpace);
symtab.addSymbol(spacesym); symtab.addSymbol(spacesym);
insertSpace(new UniqueSpace(this, "unique", numSpaces(), 0)); insertSpace(new UniqueSpace(this, numSpaces(), 0));
spacesym = new SpaceSymbol(location, getUniqueSpace()); // Temporary register spacesym = new SpaceSymbol(location, getUniqueSpace()); // Temporary register
// space // space
symtab.addSymbol(spacesym); symtab.addSymbol(spacesym);

View file

@ -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.
@ -20,14 +19,14 @@ import java.io.PrintStream;
import org.jdom.Element; import org.jdom.Element;
import ghidra.pcodeCPort.error.*; import ghidra.pcodeCPort.error.LowlevelError;
import ghidra.pcodeCPort.translate.*; import ghidra.pcodeCPort.translate.Translate;
import ghidra.program.model.lang.SpaceNames;
public class ConstantSpace extends AddrSpace { public class ConstantSpace extends AddrSpace {
public ConstantSpace( Translate t, String nm, int ind ) { public ConstantSpace(Translate t) {
super( t, spacetype.IPTR_CONSTANT, nm, 8, 1, ind, 0, 0 ); super(t, spacetype.IPTR_CONSTANT, SpaceNames.CONSTANT_SPACE_NAME, 8, 1,
SpaceNames.CONSTANT_SPACE_INDEX, 0, 0);
clearFlags(heritaged | big_endian); clearFlags(heritaged | big_endian);
setFlags(big_endian); setFlags(big_endian);
} }

View file

@ -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.
@ -16,14 +15,15 @@
*/ */
package ghidra.pcodeCPort.space; package ghidra.pcodeCPort.space;
import ghidra.pcodeCPort.translate.*;
import java.io.PrintStream; import java.io.PrintStream;
import ghidra.pcodeCPort.translate.Translate;
import ghidra.program.model.lang.SpaceNames;
public class UniqueSpace extends AddrSpace { public class UniqueSpace extends AddrSpace {
public UniqueSpace( Translate t, String nm, int ind, int fl ) { public UniqueSpace(Translate t, int ind, int fl) {
super( t, spacetype.IPTR_INTERNAL, nm, 4, 1, ind, fl, 0 ); super(t, spacetype.IPTR_INTERNAL, SpaceNames.UNIQUE_SPACE_NAME,
SpaceNames.UNIQUE_SPACE_SIZE, 1, ind, fl, 0);
setFlags(hasphysical); setFlags(hasphysical);
} }

View file

@ -28,7 +28,7 @@ import ghidra.pcodeCPort.pcoderaw.VarnodeData;
import ghidra.pcodeCPort.space.*; import ghidra.pcodeCPort.space.*;
import ghidra.pcodeCPort.utils.AddrSpaceToIdSymmetryMap; import ghidra.pcodeCPort.utils.AddrSpaceToIdSymmetryMap;
import ghidra.pcodeCPort.xml.DocumentStorage; import ghidra.pcodeCPort.xml.DocumentStorage;
import ghidra.program.model.lang.BasicCompilerSpec; import ghidra.program.model.lang.SpaceNames;
public abstract class Translate implements BasicSpaceProvider { public abstract class Translate implements BasicSpaceProvider {
@ -215,10 +215,11 @@ public abstract class Translate implements BasicSpaceProvider {
public abstract void initialize(DocumentStorage store); public abstract void initialize(DocumentStorage store);
protected void registerContext(String name, int sbit, int ebit) { protected void registerContext(String name, int sbit, int ebit) {
// Base implementation (for compiling) doesn't need to keep track of context symbol
} }
public void setContextDefault(String name, int val) { // public void setContextDefault(String name, int val) {
} // }
public abstract VarnodeData getRegister(String nm); public abstract VarnodeData getRegister(String nm);
@ -257,11 +258,11 @@ public abstract class Translate implements BasicSpaceProvider {
protected void restoreXmlSpaces(Element el) { protected void restoreXmlSpaces(Element el) {
// The first space should always be the constant space // The first space should always be the constant space
insertSpace(new ConstantSpace(this, "const", BasicCompilerSpec.CONSTANT_SPACE_INDEX)); insertSpace(new ConstantSpace(this));
// The second space should always be the other space // The second space should always be the other space
insertSpace(new OtherSpace(this, BasicCompilerSpec.OTHER_SPACE_NAME, insertSpace(
BasicCompilerSpec.OTHER_SPACE_INDEX)); new OtherSpace(this, SpaceNames.OTHER_SPACE_NAME, SpaceNames.OTHER_SPACE_INDEX));
String defname = el.getAttributeValue("defaultspace"); String defname = el.getAttributeValue("defaultspace");
List<?> children = el.getChildren(); List<?> children = el.getChildren();
@ -350,7 +351,7 @@ public abstract class Translate implements BasicSpaceProvider {
boolean duplicatedefine = false; boolean duplicatedefine = false;
switch (spc.getType()) { switch (spc.getType()) {
case IPTR_CONSTANT: case IPTR_CONSTANT:
if (!spc.getName().equals("const")) { if (!spc.getName().equals(SpaceNames.CONSTANT_SPACE_NAME)) {
nametype_mismatch = true; nametype_mismatch = true;
} }
if (baselist.size() != 0) { if (baselist.size() != 0) {
@ -359,7 +360,7 @@ public abstract class Translate implements BasicSpaceProvider {
constantspace = spc; constantspace = spc;
break; break;
case IPTR_INTERNAL: case IPTR_INTERNAL:
if (!spc.getName().equals("unique")) { if (!spc.getName().equals(SpaceNames.UNIQUE_SPACE_NAME)) {
nametype_mismatch = true; nametype_mismatch = true;
} }
if (uniqspace != null) { if (uniqspace != null) {
@ -368,7 +369,7 @@ public abstract class Translate implements BasicSpaceProvider {
uniqspace = spc; uniqspace = spc;
break; break;
case IPTR_FSPEC: case IPTR_FSPEC:
if (!spc.getName().equals("fspec")) { if (!spc.getName().equals(SpaceNames.FSPEC_SPACE_NAME)) {
nametype_mismatch = true; nametype_mismatch = true;
} }
if (fspecspace != null) { if (fspecspace != null) {
@ -377,7 +378,7 @@ public abstract class Translate implements BasicSpaceProvider {
fspecspace = spc; fspecspace = spc;
break; break;
case IPTR_IOP: case IPTR_IOP:
if (!spc.getName().equals("iop")) { if (!spc.getName().equals(SpaceNames.IOP_SPACE_NAME)) {
nametype_mismatch = true; nametype_mismatch = true;
} }
if (iopspace != null) { if (iopspace != null) {
@ -386,18 +387,16 @@ public abstract class Translate implements BasicSpaceProvider {
iopspace = spc; iopspace = spc;
break; break;
case IPTR_SPACEBASE: case IPTR_SPACEBASE:
if (spc.getName().equals("stack")) { if (spc.getName().equals(SpaceNames.STACK_SPACE_NAME)) {
if (stackspace != null) { if (stackspace != null) {
duplicatedefine = true; duplicatedefine = true;
} }
stackspace = spc; stackspace = spc;
} }
else {
}
// fallthru // fallthru
case IPTR_PROCESSOR: case IPTR_PROCESSOR:
if (spc.isOtherSpace()) { if (spc.isOtherSpace()) {
if (spc.getIndex() != BasicCompilerSpec.OTHER_SPACE_INDEX) { if (spc.getIndex() != SpaceNames.OTHER_SPACE_INDEX) {
throw new LowlevelError("OTHER space must be assigned index 1"); throw new LowlevelError("OTHER space must be assigned index 1");
} }
} }
@ -481,7 +480,8 @@ public abstract class Translate implements BasicSpaceProvider {
// Get data for the stackpointer // Get data for the stackpointer
VarnodeData point = getRegister(el.getAttributeValue("register")); VarnodeData point = getRegister(el.getAttributeValue("register"));
spc = new SpacebaseSpace("stack", ind, point.size, basespace, point.space.getDelay() + 1); spc = new SpacebaseSpace(SpaceNames.STACK_SPACE_NAME, ind, point.size, basespace,
point.space.getDelay() + 1);
insertSpace(spc); insertSpace(spc);
addSpacebase(stackspace, point.space, point.offset, point.size); addSpacebase(stackspace, point.space, point.offset, point.size);
} }
@ -554,7 +554,7 @@ public abstract class Translate implements BasicSpaceProvider {
// spaceOrderMap = SpaceOrderMap.getSpaceOrderMapForProcessor( processorFile ); // spaceOrderMap = SpaceOrderMap.getSpaceOrderMapForProcessor( processorFile );
} }
public void allowContextSet(boolean val) { // public void allowContextSet(boolean val) {
} // }
} }

View file

@ -20,7 +20,8 @@ import java.util.List;
import db.DBRecord; import db.DBRecord;
import ghidra.program.database.DBObjectCache; import ghidra.program.database.DBObjectCache;
import ghidra.program.model.address.*; import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressOverflowException;
import ghidra.program.model.lang.*; import ghidra.program.model.lang.*;
import ghidra.program.model.listing.*; import ghidra.program.model.listing.*;
import ghidra.program.model.mem.MemBuffer; import ghidra.program.model.mem.MemBuffer;
@ -128,7 +129,7 @@ public class InstructionDB extends CodeUnitDB implements Instruction, Instructio
/** /**
* Get the original context used to establish the shared prototype * Get the original context used to establish the shared prototype
* @param baseContextReg * @param baseContextReg is a context register
* @return prototype context value * @return prototype context value
*/ */
public RegisterValue getOriginalPrototypeContext(Register baseContextReg) { public RegisterValue getOriginalPrototypeContext(Register baseContextReg) {
@ -158,7 +159,8 @@ public class InstructionDB extends CodeUnitDB implements Instruction, Instructio
do { do {
// skip past delay slot instructions // skip past delay slot instructions
try { try {
instr = program.getListing().getInstructionContaining( instr = program.getListing()
.getInstructionContaining(
instr.getMinAddress().subtractNoWrap(alignment)); instr.getMinAddress().subtractNoWrap(alignment));
} }
catch (AddressOverflowException e) { catch (AddressOverflowException e) {
@ -219,10 +221,10 @@ public class InstructionDB extends CodeUnitDB implements Instruction, Instructio
return EMPTY_ADDR_ARRAY; return EMPTY_ADDR_ARRAY;
} }
ArrayList<Address> list = new ArrayList<Address>(); ArrayList<Address> list = new ArrayList<>();
for (int i = 0; i < refs.length; ++i) { for (Reference ref : refs) {
if (!refs[i].getReferenceType().isIndirect()) { if (!ref.getReferenceType().isIndirect()) {
list.add(refs[i].getToAddress()); list.add(ref.getToAddress());
} }
} }
@ -260,8 +262,7 @@ public class InstructionDB extends CodeUnitDB implements Instruction, Instructio
lock.acquire(); lock.acquire();
try { try {
checkIsValid(); checkIsValid();
return proto.getOperandRefType(opIndex, this, new InstructionPcodeOverride(this), return proto.getOperandRefType(opIndex, this, new InstructionPcodeOverride(this));
new UniqueAddressFactory(program.getAddressFactory(), program.getLanguage()));
} }
finally { finally {
lock.release(); lock.release();
@ -593,10 +594,9 @@ public class InstructionDB extends CodeUnitDB implements Instruction, Instructio
try { try {
checkIsValid(); checkIsValid();
if (!includeOverrides) { if (!includeOverrides) {
return proto.getPcode(this, null, null); return proto.getPcode(this, null);
} }
return proto.getPcode(this, new InstructionPcodeOverride(this), return proto.getPcode(this, new InstructionPcodeOverride(this));
new UniqueAddressFactory(program.getAddressFactory(), program.getLanguage()));
} }
finally { finally {
lock.release(); lock.release();

View file

@ -17,7 +17,7 @@ package ghidra.program.model.address;
import java.math.BigInteger; import java.math.BigInteger;
import ghidra.program.model.lang.BasicCompilerSpec; import ghidra.program.model.lang.SpaceNames;
import ghidra.program.model.listing.Program; import ghidra.program.model.listing.Program;
/** /**
@ -70,7 +70,7 @@ public interface AddressSpace extends Comparable<AddressSpace> {
* get loaded into the final memory image and for user-defined spaces. * get loaded into the final memory image and for user-defined spaces.
*/ */
public static final AddressSpace OTHER_SPACE = new GenericAddressSpace( public static final AddressSpace OTHER_SPACE = new GenericAddressSpace(
BasicCompilerSpec.OTHER_SPACE_NAME, 64, TYPE_OTHER, BasicCompilerSpec.OTHER_SPACE_INDEX); SpaceNames.OTHER_SPACE_NAME, 64, TYPE_OTHER, SpaceNames.OTHER_SPACE_INDEX);
/** /**
* The <code>EXTERNAL_SPACE</code> is used to contain all external locations (i.e., data and functions) * The <code>EXTERNAL_SPACE</code> is used to contain all external locations (i.e., data and functions)

View file

@ -18,7 +18,7 @@ package ghidra.program.model.address;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import ghidra.program.model.lang.BasicCompilerSpec; import ghidra.program.model.lang.SpaceNames;
import ghidra.util.datastruct.IntObjectHashtable; import ghidra.util.datastruct.IntObjectHashtable;
import ghidra.util.exception.DuplicateNameException; import ghidra.util.exception.DuplicateNameException;
@ -128,7 +128,7 @@ public class DefaultAddressFactory implements AddressFactory {
private void checkReservedJoin(AddressSpace space) { private void checkReservedJoin(AddressSpace space) {
if (space.getType() == AddressSpace.TYPE_JOIN || if (space.getType() == AddressSpace.TYPE_JOIN ||
space.getName().equals(BasicCompilerSpec.JOIN_SPACE_NAME)) { space.getName().equals(SpaceNames.JOIN_SPACE_NAME)) {
throw new IllegalArgumentException("Join space should not be specified"); throw new IllegalArgumentException("Join space should not be specified");
} }
} }
@ -142,7 +142,7 @@ public class DefaultAddressFactory implements AddressFactory {
private void checkReservedStack(AddressSpace space) { private void checkReservedStack(AddressSpace space) {
if (space.getType() == AddressSpace.TYPE_STACK || if (space.getType() == AddressSpace.TYPE_STACK ||
space.getName().equalsIgnoreCase(BasicCompilerSpec.STACK_SPACE_NAME)) { space.getName().equalsIgnoreCase(SpaceNames.STACK_SPACE_NAME)) {
throw new IllegalArgumentException("Stack space should not be specified"); throw new IllegalArgumentException("Stack space should not be specified");
} }
} }
@ -399,7 +399,7 @@ public class DefaultAddressFactory implements AddressFactory {
throw new DuplicateNameException("Space named " + space.getName() + " already exists!"); throw new DuplicateNameException("Space named " + space.getName() + " already exists!");
} }
if (space.getType() == AddressSpace.TYPE_VARIABLE) { if (space.getType() == AddressSpace.TYPE_VARIABLE) {
spaceNameTable.put("join", space);// Add VARIABLE space with name "join" spaceNameTable.put(SpaceNames.JOIN_SPACE_NAME, space);// Add VARIABLE space with name "join"
return;// Don't put it in the spaces array or the id lookup table return;// Don't put it in the spaces array or the id lookup table
} }
spaces.add(space); spaces.add(space);

View file

@ -1,54 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.program.model.address;
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
import ghidra.pcodeCPort.sleighbase.SleighBase;
import ghidra.program.model.lang.Language;
public class UniqueAddressFactory {
private AddressFactory addrFactory;
private AddressSpace uniqueSpace;
private final long firstAvailableOffset;
private long nextOffset;
public UniqueAddressFactory(AddressFactory addrFactory, Language language) {
this.addrFactory = addrFactory;
this.uniqueSpace = addrFactory.getUniqueSpace();
if (language instanceof SleighLanguage) {
firstAvailableOffset = ((SleighLanguage) language).getUniqueBase();
}
else {
firstAvailableOffset = 0;
}
nextOffset = firstAvailableOffset;
}
public synchronized Address getNextUniqueAddress() {
Address addr = uniqueSpace.getAddress(nextOffset);
nextOffset += SleighBase.MAX_UNIQUE_SIZE;
return addr;
}
public synchronized void reset() {
nextOffset = firstAvailableOffset;
}
public AddressFactory getAddressFactory() {
return addrFactory;
}
}

View file

@ -48,14 +48,6 @@ import ghidra.xml.*;
*/ */
public class BasicCompilerSpec implements CompilerSpec { public class BasicCompilerSpec implements CompilerSpec {
public static final String STACK_SPACE_NAME = "stack";
public static final String JOIN_SPACE_NAME = "join";
public static final String OTHER_SPACE_NAME = "OTHER";
//must match AddrSpace enum (see space.hh)
public static final int CONSTANT_SPACE_INDEX = 0;
public static final int OTHER_SPACE_INDEX = 1;
private final CompilerSpecDescription description; private final CompilerSpecDescription description;
private String sourceName; private String sourceName;
private final SleighLanguage language; private final SleighLanguage language;
@ -426,21 +418,21 @@ public class BasicCompilerSpec implements CompilerSpec {
@Override @Override
public AddressSpace getAddressSpace(String spaceName) { public AddressSpace getAddressSpace(String spaceName) {
AddressSpace space; AddressSpace space;
if (STACK_SPACE_NAME.equals(spaceName)) { if (SpaceNames.STACK_SPACE_NAME.equals(spaceName)) {
space = stackSpace; space = stackSpace;
} }
else if (JOIN_SPACE_NAME.equals(spaceName)) { else if (SpaceNames.JOIN_SPACE_NAME.equals(spaceName)) {
if (joinSpace == null) { if (joinSpace == null) {
// This is a special address space that is only used internally to represent bonded registers // This is a special address space that is only used internally to represent bonded registers
joinSpace = joinSpace = new GenericAddressSpace(SpaceNames.JOIN_SPACE_NAME, 64,
new GenericAddressSpace(JOIN_SPACE_NAME, 64, AddressSpace.TYPE_JOIN, 10); AddressSpace.TYPE_JOIN, 10);
} }
space = joinSpace; space = joinSpace;
} }
else { else {
space = language.getAddressFactory().getAddressSpace(spaceName); space = language.getAddressFactory().getAddressSpace(spaceName);
} }
if (spaceName.equals(OTHER_SPACE_NAME)) { if (spaceName.equals(SpaceNames.OTHER_SPACE_NAME)) {
space = AddressSpace.OTHER_SPACE; space = AddressSpace.OTHER_SPACE;
} }
if (space == null) { if (space == null) {
@ -701,7 +693,7 @@ public class BasicCompilerSpec implements CompilerSpec {
parser.end(); parser.end();
if (stackPointer == null) { if (stackPointer == null) {
stackSpace = new GenericAddressSpace(STACK_SPACE_NAME, stackSpace = new GenericAddressSpace(SpaceNames.STACK_SPACE_NAME,
language.getDefaultSpace().getSize(), language.getDefaultSpace().getSize(),
language.getDefaultSpace().getAddressableUnitSize(), AddressSpace.TYPE_STACK, 0); language.getDefaultSpace().getAddressableUnitSize(), AddressSpace.TYPE_STACK, 0);
} }
@ -979,7 +971,7 @@ public class BasicCompilerSpec implements CompilerSpec {
throw new SleighException("Undefined base stack space: " + baseSpaceName); throw new SleighException("Undefined base stack space: " + baseSpaceName);
} }
int stackSpaceSize = Math.min(stackPointer.getBitLength(), stackBaseSpace.getSize()); int stackSpaceSize = Math.min(stackPointer.getBitLength(), stackBaseSpace.getSize());
stackSpace = new GenericAddressSpace(STACK_SPACE_NAME, stackSpaceSize, stackSpace = new GenericAddressSpace(SpaceNames.STACK_SPACE_NAME, stackSpaceSize,
stackBaseSpace.getAddressableUnitSize(), AddressSpace.TYPE_STACK, 0); stackBaseSpace.getAddressableUnitSize(), AddressSpace.TYPE_STACK, 0);
String reverseJustifyStr = el.getAttribute("reversejustify"); String reverseJustifyStr = el.getAttribute("reversejustify");
if (reverseJustifyStr != null) { if (reverseJustifyStr != null) {

View file

@ -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.
@ -16,8 +15,9 @@
*/ */
package ghidra.program.model.lang; package ghidra.program.model.lang;
import java.util.ArrayList;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.address.UniqueAddressFactory;
import ghidra.program.model.mem.MemBuffer; import ghidra.program.model.mem.MemBuffer;
import ghidra.program.model.mem.MemoryAccessException; import ghidra.program.model.mem.MemoryAccessException;
import ghidra.program.model.pcode.PcodeOp; import ghidra.program.model.pcode.PcodeOp;
@ -26,8 +26,6 @@ import ghidra.program.model.scalar.Scalar;
import ghidra.program.model.symbol.FlowType; import ghidra.program.model.symbol.FlowType;
import ghidra.program.model.symbol.RefType; import ghidra.program.model.symbol.RefType;
import java.util.ArrayList;
/** /**
* InstructionPrototype is designed to describe one machine level instruction. * InstructionPrototype is designed to describe one machine level instruction.
* A language parser can return the same InstructionProtoype object for the * A language parser can return the same InstructionProtoype object for the
@ -252,11 +250,10 @@ public interface InstructionPrototype {
* @param opIndex the index of the operand. (zero based) * @param opIndex the index of the operand. (zero based)
* @param context the instruction context * @param context the instruction context
* @param override if not null, steers local overrides of pcode generation * @param override if not null, steers local overrides of pcode generation
* @param uniqueFactory must be specified if flowOverride is not null
* @return reference type. * @return reference type.
*/ */
public RefType getOperandRefType(int opIndex, InstructionContext context, public RefType getOperandRefType(int opIndex, InstructionContext context,
PcodeOverride override, UniqueAddressFactory uniqueFactory); PcodeOverride override);
/** /**
* Return true if the operand at opIndex should have a delimiter following it. * Return true if the operand at opIndex should have a delimiter following it.
@ -290,22 +287,18 @@ public interface InstructionPrototype {
* *
* @param context the instruction context * @param context the instruction context
* @param override if not null, may indicate that different elements of the pcode generation are overridden * @param override if not null, may indicate that different elements of the pcode generation are overridden
* @param uniqueFactory must be specified if flowOverride is not null
* @return array of PCODE, * @return array of PCODE,
* zero length array if language doesn't support PCODE for this instruction * zero length array if language doesn't support PCODE for this instruction
*/ */
public PcodeOp[] getPcode(InstructionContext context, PcodeOverride override, public PcodeOp[] getPcode(InstructionContext context, PcodeOverride override);
UniqueAddressFactory uniqueFactory);
/** /**
* Same as getPcode but returns the operations in a packed format to optimize transfer to other processes * Same as getPcode but returns the operations in a packed format to optimize transfer to other processes
* @param context the instruction context * @param context the instruction context
* @param override if not null, may indicate that different elements of the pcode generation are overridden * @param override if not null, may indicate that different elements of the pcode generation are overridden
* @param uniqueFactory must be specified if flowOverride is not null * @return the set of packed bytes encoding the p-code
* @return
*/ */
public PackedBytes getPcodePacked(InstructionContext context, PcodeOverride override, public PackedBytes getPcodePacked(InstructionContext context, PcodeOverride override);
UniqueAddressFactory uniqueFactory);
/** /**
* Get an array of PCode operations (micro code) that a particular operand * Get an array of PCode operations (micro code) that a particular operand

View file

@ -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.
@ -16,8 +15,9 @@
*/ */
package ghidra.program.model.lang; package ghidra.program.model.lang;
import java.util.ArrayList;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.address.UniqueAddressFactory;
import ghidra.program.model.mem.MemBuffer; import ghidra.program.model.mem.MemBuffer;
import ghidra.program.model.mem.MemoryAccessException; import ghidra.program.model.mem.MemoryAccessException;
import ghidra.program.model.pcode.PcodeOp; import ghidra.program.model.pcode.PcodeOp;
@ -26,8 +26,6 @@ import ghidra.program.model.scalar.Scalar;
import ghidra.program.model.symbol.FlowType; import ghidra.program.model.symbol.FlowType;
import ghidra.program.model.symbol.RefType; import ghidra.program.model.symbol.RefType;
import java.util.ArrayList;
/** /**
* Class to represent an invalid instruction prototype. * Class to represent an invalid instruction prototype.
*/ */
@ -39,6 +37,7 @@ public class InvalidPrototype implements InstructionPrototype, ParserContext {
/** /**
* Construct a new invalid instruction prototype. * Construct a new invalid instruction prototype.
* @param lang is the Language for which the invalid instruction is discovered
*/ */
public InvalidPrototype(Language lang) { public InvalidPrototype(Language lang) {
super(); super();
@ -151,14 +150,12 @@ public class InvalidPrototype implements InstructionPrototype, ParserContext {
} }
@Override @Override
public PcodeOp[] getPcode(InstructionContext context, PcodeOverride override, public PcodeOp[] getPcode(InstructionContext context, PcodeOverride override) {
UniqueAddressFactory uniqueFactory) {
return new PcodeOp[] { new PcodeOp(context.getAddress(), 0, PcodeOp.UNIMPLEMENTED) }; return new PcodeOp[] { new PcodeOp(context.getAddress(), 0, PcodeOp.UNIMPLEMENTED) };
} }
@Override @Override
public PackedBytes getPcodePacked(InstructionContext context, PcodeOverride override, public PackedBytes getPcodePacked(InstructionContext context, PcodeOverride override) {
UniqueAddressFactory uniqueFactory) {
return null; return null;
} }
@ -184,7 +181,7 @@ public class InvalidPrototype implements InstructionPrototype, ParserContext {
@Override @Override
public RefType getOperandRefType(int opIndex, InstructionContext context, public RefType getOperandRefType(int opIndex, InstructionContext context,
PcodeOverride override, UniqueAddressFactory uniqueFactory) { PcodeOverride override) {
return null; return null;
} }

View file

@ -19,20 +19,15 @@ import java.io.IOException;
import java.util.*; import java.util.*;
import java.util.Map.Entry; import java.util.Map.Entry;
import org.jdom.JDOMException; import ghidra.app.plugin.processors.sleigh.*;
import org.xml.sax.*; import ghidra.app.plugin.processors.sleigh.template.ConstructTpl;
import ghidra.app.plugin.processors.sleigh.SleighException;
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
import ghidra.app.plugin.processors.sleigh.template.*;
import ghidra.pcodeCPort.sleighbase.SleighBase;
import ghidra.pcodeCPort.slgh_compile.PcodeParser;
import ghidra.program.model.lang.InjectPayload.InjectParameter; import ghidra.program.model.lang.InjectPayload.InjectParameter;
import ghidra.program.model.listing.Program; import ghidra.program.model.listing.Program;
import ghidra.sleigh.grammar.Location; import ghidra.sleigh.grammar.Location;
import ghidra.util.Msg; import ghidra.util.Msg;
import ghidra.util.SystemUtilities; import ghidra.util.SystemUtilities;
import ghidra.xml.*; import ghidra.xml.XmlParseException;
import ghidra.xml.XmlPullParser;
public class PcodeInjectLibrary { public class PcodeInjectLibrary {
protected SleighLanguage language; protected SleighLanguage language;
@ -47,7 +42,7 @@ public class PcodeInjectLibrary {
public PcodeInjectLibrary(SleighLanguage l) { public PcodeInjectLibrary(SleighLanguage l) {
language = l; language = l;
uniqueBase = language.getUniqueBase(); uniqueBase = UniqueLayout.INJECT.getOffset(l);
callFixupMap = new TreeMap<>(); callFixupMap = new TreeMap<>();
callOtherFixupMap = new TreeMap<>(); callOtherFixupMap = new TreeMap<>();
callOtherOverride = null; callOtherOverride = null;
@ -168,11 +163,7 @@ public class PcodeInjectLibrary {
return; // Dynamic p-code generation, or already parsed return; // Dynamic p-code generation, or already parsed
} }
String translateSpec = language.buildTranslatorTag(language.getAddressFactory(), uniqueBase, PcodeParser parser = new PcodeParser(language, uniqueBase);
language.getSymbolTable());
try {
PcodeParser parser = new PcodeParser(translateSpec);
Location loc = new Location(sourceName, 1); Location loc = new Location(sourceName, 1);
InjectParameter[] input = payload.getInput(); InjectParameter[] input = payload.getInput();
for (InjectParameter element : input) { for (InjectParameter element : input) {
@ -182,77 +173,12 @@ public class PcodeInjectLibrary {
for (InjectParameter element : output) { for (InjectParameter element : output) {
parser.addOperand(loc, element.getName(), element.getIndex()); parser.addOperand(loc, element.getName(), element.getIndex());
} }
String constructTplXml = ConstructTpl constructTpl = parser.compilePcode(pcodeText, sourceName, 1);
PcodeParser.stringifyTemplate(parser.compilePcode(pcodeText, sourceName, 1));
if (constructTplXml == null) {
throw new SleighException("pcode compile failed " + sourceName);
}
final SAXParseException[] exception = new SAXParseException[1];
XmlPullParser xmlParser =
XmlPullParserFactory.create(constructTplXml, sourceName, new ErrorHandler() {
@Override
public void warning(SAXParseException e) throws SAXException {
Msg.warn(this, e.getMessage());
}
@Override uniqueBase = parser.getNextTempOffset();
public void fatalError(SAXParseException e) throws SAXException {
exception[0] = e;
}
@Override
public void error(SAXParseException e) throws SAXException {
exception[0] = e;
}
}, false);
ConstructTpl constructTpl = new ConstructTpl();
constructTpl.restoreXml(xmlParser, language.getAddressFactory());
if (exception[0] != null) {
throw new SleighException("pcode compiler returned invalid xml " + sourceName,
exception[0]);
}
OpTpl[] opTemplates = constructTpl.getOpVec();
adjustUniqueBase(opTemplates);
payloadSleigh.setTemplate(constructTpl); payloadSleigh.setTemplate(constructTpl);
} }
catch (UnknownInstructionException e) {
throw new SleighException("compiled pcode contains invalid opcode " + sourceName, e);
}
catch (JDOMException e) {
throw new SleighException(
"pcode compile failed due to invalid translator tag " + sourceName, e);
}
catch (SAXException e) {
throw new SleighException("pcode compiler returned invalid xml " + sourceName, e);
}
}
//changed to protected for PcodeInjectLibraryJava
protected void adjustUniqueBase(OpTpl[] opTemplates) {
for (OpTpl opt : opTemplates) {
VarnodeTpl out = opt.getOutput();
if (out != null) {
adjustUniqueBase(out);
}
for (VarnodeTpl in : opt.getInput()) {
adjustUniqueBase(in);
}
}
}
private void adjustUniqueBase(VarnodeTpl v) {
ConstTpl space = v.getSpace();
if (!space.isUniqueSpace()) {
return;
}
ConstTpl c = v.getOffset();
long offset = c.getReal();
if (offset >= uniqueBase) {
uniqueBase = offset + SleighBase.MAX_UNIQUE_SIZE;
}
}
/** /**
* @return a list of names for all installed call-fixups * @return a list of names for all installed call-fixups

View file

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package ghidra.pcodeCPort.slgh_compile; package ghidra.program.model.lang;
import java.io.*; import java.io.*;
import java.util.*; import java.util.*;
@ -21,32 +21,39 @@ import java.util.stream.Collectors;
import org.antlr.runtime.*; import org.antlr.runtime.*;
import org.antlr.runtime.tree.CommonTreeNodeStream; import org.antlr.runtime.tree.CommonTreeNodeStream;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jdom.*;
import generic.stl.VectorSTL; import generic.stl.VectorSTL;
import ghidra.app.plugin.processors.sleigh.SleighException; import ghidra.app.plugin.processors.sleigh.*;
import ghidra.app.plugin.processors.sleigh.SleighLanguage; import ghidra.app.plugin.processors.sleigh.symbol.Symbol;
import ghidra.app.plugin.processors.sleigh.symbol.SymbolTable;
import ghidra.app.plugin.processors.sleigh.symbol.UseropSymbol;
import ghidra.app.plugin.processors.sleigh.symbol.VarnodeSymbol;
import ghidra.app.plugin.processors.sleigh.template.*;
import ghidra.pcode.utils.MessageFormattingUtils; import ghidra.pcode.utils.MessageFormattingUtils;
import ghidra.pcodeCPort.address.Address; import ghidra.pcodeCPort.address.Address;
import ghidra.pcodeCPort.context.SleighError; import ghidra.pcodeCPort.context.SleighError;
import ghidra.pcodeCPort.error.LowlevelError;
import ghidra.pcodeCPort.semantics.*;
import ghidra.pcodeCPort.sleighbase.SleighBase; import ghidra.pcodeCPort.sleighbase.SleighBase;
import ghidra.pcodeCPort.slgh_compile.*;
import ghidra.pcodeCPort.slghsymbol.*; import ghidra.pcodeCPort.slghsymbol.*;
import ghidra.pcodeCPort.space.AddrSpace; import ghidra.pcodeCPort.slghsymbol.EndSymbol;
import ghidra.pcodeCPort.utils.XmlUtils; import ghidra.pcodeCPort.slghsymbol.OperandSymbol;
import ghidra.pcodeCPort.slghsymbol.StartSymbol;
import ghidra.pcodeCPort.space.*;
import ghidra.pcodeCPort.xml.DocumentStorage; import ghidra.pcodeCPort.xml.DocumentStorage;
import ghidra.program.model.address.*;
import ghidra.sleigh.grammar.*; import ghidra.sleigh.grammar.*;
import ghidra.sleigh.grammar.SleighParser_SemanticParser.semantic_return; import ghidra.sleigh.grammar.SleighParser_SemanticParser.semantic_return;
import ghidra.util.exception.AssertException; import ghidra.util.exception.AssertException;
/**
* This class is intended to parse p-code snippets, typically from compiler specification files
* or extensions. This is outside the normal SLEIGH compilation process, and the parser is built
* on top of an existing SleighLanguage.
*/
public class PcodeParser extends PcodeCompile { public class PcodeParser extends PcodeCompile {
public final static Logger log = LogManager.getLogger(PcodeParser.class);
private SleighBase sleigh; private SleighBase sleigh;
private AddressFactory addrFactory;
private long tempbase; private long tempbase;
private HashMap<String, SleighSymbol> symbolMap = new HashMap<>(); private HashMap<String, SleighSymbol> symbolMap = new HashMap<>();
@ -60,25 +67,14 @@ public class PcodeParser extends PcodeCompile {
} }
/** /**
* Build parser from a translator string * Build parser from an existing SleighLanguage.
* @param sleighSpec sleigh translator spec including address-spaces and register definitions, see * @param language is the existing language
* {@link SleighLanguage#buildTranslatorTag(ghidra.program.model.address.AddressFactory, long, ghidra.app.plugin.processors.sleigh.symbol.SymbolTable, boolean)} * @param ubase is the starting offset for allocating temporary registers
* @throws JDOMException
*/ */
public PcodeParser(String sleighSpec) throws JDOMException { public PcodeParser(SleighLanguage language, long ubase) {
DocumentStorage store = new DocumentStorage();
Document doc = null;
try {
doc = store.parseDocument(new StringBufferInputStream(sleighSpec));
}
catch (IOException e) {
throw new AssertException(); // unexpected on string
}
store.registerTag(doc.getRootElement());
PcodeTranslate translate = new PcodeTranslate(); addrFactory = language.getAddressFactory();
translate.initialize(store); sleigh = new PcodeTranslate(language, ubase);
sleigh = translate;
initializeSymbols(); initializeSymbols();
} }
@ -97,6 +93,7 @@ public class PcodeParser extends PcodeCompile {
* Inject a symbol representing an "operand" to the pcode snippet. This puts a placeholder in the * Inject a symbol representing an "operand" to the pcode snippet. This puts a placeholder in the
* resulting template, which gets filled in with the context specific storage locations when final * resulting template, which gets filled in with the context specific storage locations when final
* p-code is generated * p-code is generated
* @param loc is location information for the operand
* @param name of operand symbol * @param name of operand symbol
* @param index to use for the placeholder * @param index to use for the placeholder
*/ */
@ -130,6 +127,10 @@ public class PcodeParser extends PcodeCompile {
currentSymbols.clear(); currentSymbols.clear();
} }
public long getNextTempOffset() {
return tempbase;
}
@Override @Override
public long allocateTemp() { public long allocateTemp() {
long base = tempbase; long base = tempbase;
@ -138,8 +139,8 @@ public class PcodeParser extends PcodeCompile {
} }
@Override @Override
public VectorSTL<OpTpl> createMacroUse(Location location, MacroSymbol sym, public VectorSTL<ghidra.pcodeCPort.semantics.OpTpl> createMacroUse(Location location,
VectorSTL<ExprTree> param) { MacroSymbol sym, VectorSTL<ExprTree> param) {
throw new SleighError("Pcode snippet parsing does not support use of macros", location); throw new SleighError("Pcode snippet parsing does not support use of macros", location);
} }
@ -169,6 +170,7 @@ public class PcodeParser extends PcodeCompile {
@Override @Override
public void recordNop(Location location) { public void recordNop(Location location) {
// No NOP statistics collected for snippet parsing
} }
// Make sure label symbols are used properly // Make sure label symbols are used properly
@ -193,7 +195,7 @@ public class PcodeParser extends PcodeCompile {
} }
private ConstructTpl buildConstructor(ConstructTpl rtl) { private ConstructTpl buildConstructor(ghidra.pcodeCPort.semantics.ConstructTpl rtl) {
String errstring = ""; String errstring = "";
if (rtl != null) { if (rtl != null) {
errstring = checkLabels(); errstring = checkLabels();
@ -210,38 +212,99 @@ public class PcodeParser extends PcodeCompile {
if (errstring.length() != 0) { if (errstring.length() != 0) {
throw new SleighException(errstring); throw new SleighException(errstring);
} }
return rtl; return translateConstructTpl(rtl);
} }
/**
* This class wraps on existing SleighLanguage with the SleighBase interface expected by
* PcodeCompile. It populates the symbol table with user-defined operations and the global
* VarnodeSymbol objects, which typically includes all the general purpose registers.
*/
private static class PcodeTranslate extends SleighBase { private static class PcodeTranslate extends SleighBase {
@Override private void copySpaces(SleighLanguage language) {
public void initialize(DocumentStorage store) { insertSpace(new ConstantSpace(this));
Element el = store.getTag("sleigh"); insertSpace(
if (el == null) { new OtherSpace(this, SpaceNames.OTHER_SPACE_NAME, SpaceNames.OTHER_SPACE_INDEX));
throw new LowlevelError("Could not find sleigh tag"); AddressSpace[] spaces = language.getAddressFactory().getAllAddressSpaces();
for (AddressSpace spc : spaces) {
if (spc.getUnique() < 2) {
continue;
} }
target_endian = XmlUtils.decodeBoolean(el.getAttributeValue("bigendian")) ? 1 : 0; AddrSpace resSpace;
alignment = XmlUtils.decodeUnknownInt(el.getAttributeValue("align")); int sz = spc.getSize();
long ubase = XmlUtils.decodeUnknownLong(el.getAttributeValue("uniqbase")); if (spc instanceof SegmentedAddressSpace) {
// TODO: SegmentedAddressSpace shouldn't really return 21
sz = 32;
}
if (sz > 64) {
sz = 64;
}
int bytesize = (sz + 7) / 8; // Convert bits to bytes
switch (spc.getType()) {
case AddressSpace.TYPE_UNIQUE:
resSpace = new UniqueSpace(this, spc.getUnique(), 0);
break;
case AddressSpace.TYPE_OTHER:
resSpace = new OtherSpace(this, spc.getName(), spc.getUnique());
break;
case AddressSpace.TYPE_RAM:
resSpace = new AddrSpace(this, spacetype.IPTR_PROCESSOR, spc.getName(),
bytesize, spc.getAddressableUnitSize(), spc.getUnique(),
AddrSpace.hasphysical, 1);
break;
case AddressSpace.TYPE_REGISTER:
resSpace = new AddrSpace(this, spacetype.IPTR_PROCESSOR, spc.getName(),
bytesize, spc.getAddressableUnitSize(), spc.getUnique(),
AddrSpace.hasphysical, 0);
break;
default:
resSpace = null;
}
if (resSpace == null) {
break;
}
insertSpace(resSpace);
}
setDefaultSpace(language.getDefaultSpace().getUnique());
}
/**
* Populate the predefined symbol table for the parser from the given SLEIGH language.
* We only use user-defined op symbols and varnode symbols.
* @param language is the SLEIGH language
*/
private void copySymbols(SleighLanguage language) {
SymbolTable langTable = language.getSymbolTable();
symtab.addScope(); // Global scope
for (Symbol sym : langTable.getSymbolList()) {
if (sym instanceof UseropSymbol) {
UserOpSymbol cloneSym = new UserOpSymbol(null, sym.getName());
cloneSym.setIndex(((UseropSymbol) sym).getIndex());
symtab.addSymbol(cloneSym);
}
else if (sym instanceof VarnodeSymbol) {
VarnodeData vData = ((VarnodeSymbol) sym).getFixedVarnode();
if ("contextreg".equals(sym.getName())) {
continue;
}
ghidra.pcodeCPort.slghsymbol.VarnodeSymbol cloneSym;
AddrSpace base = getSpace(vData.space.getUnique());
cloneSym = new ghidra.pcodeCPort.slghsymbol.VarnodeSymbol(null, sym.getName(),
base, vData.offset, vData.size);
symtab.addSymbol(cloneSym);
}
}
}
public PcodeTranslate(SleighLanguage language, long ubase) {
super();
target_endian = language.isBigEndian() ? 1 : 0;
alignment = 0;
setUniqueBase(ubase); setUniqueBase(ubase);
List<?> list = el.getChildren(); copySpaces(language);
Iterator<?> iter = list.iterator(); copySymbols(language);
Element child = (Element) iter.next();
while (child.getName().equals("floatformat")) {
child = (Element) iter.next(); // skip over
}
restoreXmlSpaces(child);
child = (Element) iter.next();
while ("truncate_space".equals(child.getName())) {
// TODO: do we care about space truncations ?
child = (Element) iter.next();
}
symtab.restoreXml(child, this);
for (int i = 0; i < numSpaces(); i++) { for (int i = 0; i < numSpaces(); i++) {
AddrSpace space = getSpace(i); AddrSpace space = getSpace(i);
@ -250,29 +313,77 @@ public class PcodeParser extends PcodeCompile {
} }
@Override @Override
public int instructionLength(Address baseaddr) { public void initialize(DocumentStorage store) {
return 0; // Unused
} }
@Override @Override
public int printAssembly(PrintStream s, int size, Address baseaddr) { public int printAssembly(PrintStream s, int size, Address baseaddr) {
return 0; return 0;
} }
@Override
public int instructionLength(Address baseaddr) {
return 0;
}
} }
public static String stringifyTemplate(ConstructTpl ctl) { public ConstructTpl translateConstructTpl(
ghidra.pcodeCPort.semantics.ConstructTpl constructTpl) {
if (ctl == null) { HandleTpl handle = null;
return null; if (constructTpl.getResult() != null) {
handle = translateHandleTpl(constructTpl.getResult());
} }
ByteArrayOutputStream out = new ByteArrayOutputStream(); OpTpl[] vec = new OpTpl[constructTpl.getOpvec().size()];
ctl.saveXml(new PrintStream(out), -1); // for main section? for (int i = 0; i < vec.length; ++i) {
return out.toString(); vec[i] = translateOpTpl(constructTpl.getOpvec().get(i));
}
return new ConstructTpl(vec, handle, constructTpl.numLabels());
}
public HandleTpl translateHandleTpl(ghidra.pcodeCPort.semantics.HandleTpl handleTpl) {
return new HandleTpl(translateConstTpl(handleTpl.getSpace()),
translateConstTpl(handleTpl.getSize()), translateConstTpl(handleTpl.getPtrSpace()),
translateConstTpl(handleTpl.getPtrOffset()), translateConstTpl(handleTpl.getPtrSize()),
translateConstTpl(handleTpl.getTempSpace()),
translateConstTpl(handleTpl.getTempOffset()));
}
public OpTpl translateOpTpl(ghidra.pcodeCPort.semantics.OpTpl opTpl) {
VarnodeTpl output = null;
if (opTpl.getOut() != null) {
output = translateVarnodeTpl(opTpl.getOut());
}
VarnodeTpl[] input = new VarnodeTpl[opTpl.numInput()];
for (int i = 0; i < input.length; ++i) {
input[i] = translateVarnodeTpl(opTpl.getIn(i));
}
return new OpTpl(opTpl.getOpcode().ordinal(), output, input);
}
public VarnodeTpl translateVarnodeTpl(ghidra.pcodeCPort.semantics.VarnodeTpl varnodeTpl) {
return new VarnodeTpl(translateConstTpl(varnodeTpl.getSpace()),
translateConstTpl(varnodeTpl.getOffset()), translateConstTpl(varnodeTpl.getSize()));
}
public ConstTpl translateConstTpl(ghidra.pcodeCPort.semantics.ConstTpl constTpl) {
AddrSpace spc = constTpl.getSpace();
AddressSpace resSpace = null;
if (spc != null) {
resSpace = addrFactory.getAddressSpace(spc.getName());
}
int select = 0;
ghidra.pcodeCPort.semantics.ConstTpl.v_field field = constTpl.getSelect();
if (field != null) {
select = field.ordinal();
}
return new ConstTpl(constTpl.getType().ordinal(), constTpl.getReal(), resSpace,
constTpl.getHandleIndex(), select);
} }
/** /**
* Compile pcode semantic statements. * Compile pcode semantic statements.
* @param pcodeStatements * @param pcodeStatements is the raw source to parse
* @param srcFile source filename from which pcodeStatements came ( * @param srcFile source filename from which pcodeStatements came (
* @param srcLine line number in srcFile corresponding to pcodeStatements * @param srcLine line number in srcFile corresponding to pcodeStatements
* @return ConstructTpl. A null may be returned or * @return ConstructTpl. A null may be returned or
@ -357,32 +468,35 @@ public class PcodeParser extends PcodeCompile {
} }
@Override @Override
public VectorSTL<OpTpl> createCrossBuild(Location where, VarnodeTpl v, SectionSymbol second) { public VectorSTL<ghidra.pcodeCPort.semantics.OpTpl> createCrossBuild(Location where,
ghidra.pcodeCPort.semantics.VarnodeTpl v, SectionSymbol second) {
throw new SleighError("Pcode snippet parsing does not support use of sections", where); throw new SleighError("Pcode snippet parsing does not support use of sections", where);
} }
@Override @Override
public SectionVector standaloneSection(ConstructTpl main) { public SectionVector standaloneSection(ghidra.pcodeCPort.semantics.ConstructTpl main) {
// Create SectionVector for just the main rtl section with no named sections // Create SectionVector for just the main rtl section with no named sections
SectionVector res = new SectionVector(main, null); SectionVector res = new SectionVector(main, null);
return res; return res;
} }
@Override @Override
public SectionVector firstNamedSection(ConstructTpl main, SectionSymbol sym) { public SectionVector firstNamedSection(ghidra.pcodeCPort.semantics.ConstructTpl main,
throw new SleighError("Pcode snippet parsing does not support use of sections",
sym.location);
}
@Override
public SectionVector nextNamedSection(SectionVector vec, ConstructTpl section,
SectionSymbol sym) { SectionSymbol sym) {
throw new SleighError("Pcode snippet parsing does not support use of sections", throw new SleighError("Pcode snippet parsing does not support use of sections",
sym.location); sym.location);
} }
@Override @Override
public SectionVector finalNamedSection(SectionVector vec, ConstructTpl section) { public SectionVector nextNamedSection(SectionVector vec,
ghidra.pcodeCPort.semantics.ConstructTpl section, SectionSymbol sym) {
throw new SleighError("Pcode snippet parsing does not support use of sections",
sym.location);
}
@Override
public SectionVector finalNamedSection(SectionVector vec,
ghidra.pcodeCPort.semantics.ConstructTpl section) {
throw new SleighError("Pcode snippet parsing does not support use of sections", null); // can never get here throw new SleighError("Pcode snippet parsing does not support use of sections", null); // can never get here
} }
} }

View file

@ -0,0 +1,37 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.program.model.lang;
/**
* Reserved AddressSpace names across architectures and associated attributes
*/
public class SpaceNames {
public static final String CONSTANT_SPACE_NAME = "const"; // P-code constants
public static final String UNIQUE_SPACE_NAME = "unique"; // Temporary p-code registers
public static final String STACK_SPACE_NAME = "stack"; // Storage for stack relative varnodes
public static final String JOIN_SPACE_NAME = "join"; // Logical storage for joined varnodes
public static final String OTHER_SPACE_NAME = "OTHER"; // Other space
public static final String IOP_SPACE_NAME = "iop"; // Internal p-code reference space
public static final String FSPEC_SPACE_NAME = "fspec"; // Internal CALL reference
// must match ConstantSpace::INDEX (see space.hh)
public static final int CONSTANT_SPACE_INDEX = 0; // Index for constant space is always 0
// must match OtherSpace::INDEX (see space.hh)
public static final int OTHER_SPACE_INDEX = 1; // Index for other space is always 1
public static final int UNIQUE_SPACE_SIZE = 4; // Number of bytes for a unique offset
}

View file

@ -18,9 +18,9 @@ package ghidra.program.model.listing;
import java.util.List; import java.util.List;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.address.UniqueAddressFactory;
import ghidra.program.model.lang.*; import ghidra.program.model.lang.*;
import ghidra.program.model.pcode.PcodeOp; import ghidra.program.model.pcode.PcodeOp;
import ghidra.program.model.pcode.PcodeOverride;
import ghidra.program.model.symbol.FlowType; import ghidra.program.model.symbol.FlowType;
import ghidra.program.model.symbol.RefType; import ghidra.program.model.symbol.RefType;

View file

@ -25,8 +25,7 @@ import ghidra.program.database.function.FunctionDB;
import ghidra.program.database.symbol.CodeSymbol; import ghidra.program.database.symbol.CodeSymbol;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressOutOfBoundsException; import ghidra.program.model.address.AddressOutOfBoundsException;
import ghidra.program.model.lang.CompilerSpec; import ghidra.program.model.lang.*;
import ghidra.program.model.lang.Language;
import ghidra.program.model.listing.*; import ghidra.program.model.listing.*;
import ghidra.program.model.symbol.*; import ghidra.program.model.symbol.*;
import ghidra.util.Msg; import ghidra.util.Msg;
@ -64,7 +63,7 @@ public class HighFunction extends PcodeSyntaxTree {
func = function; func = function;
this.language = language; this.language = language;
this.compilerSpec = compilerSpec; this.compilerSpec = compilerSpec;
localSymbols = new LocalSymbolMap(this, "stack"); localSymbols = new LocalSymbolMap(this, SpaceNames.STACK_SPACE_NAME);
globalSymbols = new GlobalSymbolMap(this); globalSymbols = new GlobalSymbolMap(this);
proto = new FunctionPrototype(localSymbols, function); proto = new FunctionPrototype(localSymbols, function);
jumpTables = null; jumpTables = null;

View file

@ -27,6 +27,7 @@ import ghidra.pcode.error.LowlevelError;
import ghidra.pcode.memstate.UniqueMemoryBank.WordInfo; import ghidra.pcode.memstate.UniqueMemoryBank.WordInfo;
import ghidra.program.model.address.AddressSpace; import ghidra.program.model.address.AddressSpace;
import ghidra.program.model.address.GenericAddressSpace; import ghidra.program.model.address.GenericAddressSpace;
import ghidra.program.model.lang.SpaceNames;
public class UniqueMemoryBankTest extends AbstractGenericTest { public class UniqueMemoryBankTest extends AbstractGenericTest {
@ -39,7 +40,8 @@ public class UniqueMemoryBankTest extends AbstractGenericTest {
@Before @Before
public void setUp() { public void setUp() {
uniqueSpace = new GenericAddressSpace("unique", 64, AddressSpace.TYPE_UNIQUE, 0); uniqueSpace =
new GenericAddressSpace(SpaceNames.UNIQUE_SPACE_NAME, 64, AddressSpace.TYPE_UNIQUE, 0);
uniqueBank = new UniqueMemoryBank(uniqueSpace, false); uniqueBank = new UniqueMemoryBank(uniqueSpace, false);
} }

View file

@ -20,6 +20,7 @@ import static org.junit.Assert.*;
import org.junit.*; import org.junit.*;
import generic.test.AbstractGenericTest; import generic.test.AbstractGenericTest;
import ghidra.program.model.lang.SpaceNames;
public class AddressMapImplTest extends AbstractGenericTest { public class AddressMapImplTest extends AbstractGenericTest {
AddressSpace sp8; AddressSpace sp8;
@ -49,7 +50,8 @@ public class AddressMapImplTest extends AbstractGenericTest {
segSpace2 = new SegmentedAddressSpace("SegSpaceTwo", 4); segSpace2 = new SegmentedAddressSpace("SegSpaceTwo", 4);
regSpace = new GenericAddressSpace("Register", 32, AddressSpace.TYPE_REGISTER, 0); regSpace = new GenericAddressSpace("Register", 32, AddressSpace.TYPE_REGISTER, 0);
stackSpace = new GenericAddressSpace("stack", 32, AddressSpace.TYPE_STACK, 0); stackSpace =
new GenericAddressSpace(SpaceNames.STACK_SPACE_NAME, 32, AddressSpace.TYPE_STACK, 0);
map = new AddressMapImpl(); map = new AddressMapImpl();

View file

@ -20,6 +20,7 @@ import static org.junit.Assert.*;
import org.junit.*; import org.junit.*;
import generic.test.AbstractGenericTest; import generic.test.AbstractGenericTest;
import ghidra.program.model.lang.SpaceNames;
import ghidra.util.exception.DuplicateNameException; import ghidra.util.exception.DuplicateNameException;
public class GenericAddressTest extends AbstractGenericTest { public class GenericAddressTest extends AbstractGenericTest {
@ -37,7 +38,8 @@ public class GenericAddressTest extends AbstractGenericTest {
space2 = new GenericAddressSpace("Test2", 8, AddressSpace.TYPE_RAM, 1); space2 = new GenericAddressSpace("Test2", 8, AddressSpace.TYPE_RAM, 1);
wordSpace = new GenericAddressSpace("Test3", 16, 2, AddressSpace.TYPE_RAM, 1); wordSpace = new GenericAddressSpace("Test3", 16, 2, AddressSpace.TYPE_RAM, 1);
regSpace = new GenericAddressSpace("Register", 8, AddressSpace.TYPE_REGISTER, 0); regSpace = new GenericAddressSpace("Register", 8, AddressSpace.TYPE_REGISTER, 0);
stackSpace = new GenericAddressSpace("stack", 8, AddressSpace.TYPE_STACK, 0); stackSpace =
new GenericAddressSpace(SpaceNames.STACK_SPACE_NAME, 8, AddressSpace.TYPE_STACK, 0);
factory = factory =
new TestAddressFactory(new AddressSpace[] { space, space2, regSpace }, stackSpace); new TestAddressFactory(new AddressSpace[] { space, space2, regSpace }, stackSpace);
space = factory.getAddressSpace(space.getName()); space = factory.getAddressSpace(space.getName());

View file

@ -15,21 +15,22 @@
*/ */
package ghidra.program.model.pcode; package ghidra.program.model.pcode;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.*;
import org.junit.Test; import org.junit.Test;
import generic.test.AbstractGenericTest; import generic.test.AbstractGenericTest;
import ghidra.program.model.address.AddressSpace; import ghidra.program.model.address.AddressSpace;
import ghidra.program.model.address.GenericAddressSpace; import ghidra.program.model.address.GenericAddressSpace;
import ghidra.program.model.lang.SpaceNames;
public class VarnodeTest extends AbstractGenericTest { public class VarnodeTest extends AbstractGenericTest {
private static AddressSpace ramSpace = new GenericAddressSpace("ram", 64, private static AddressSpace ramSpace =
AddressSpace.TYPE_RAM, 0); new GenericAddressSpace("ram", 64, AddressSpace.TYPE_RAM, 0);
private static AddressSpace stackSpace = new GenericAddressSpace("stack", ramSpace.getSize(), private static AddressSpace stackSpace = new GenericAddressSpace(SpaceNames.STACK_SPACE_NAME,
ramSpace.getAddressableUnitSize(), AddressSpace.TYPE_STACK, 0); ramSpace.getSize(), ramSpace.getAddressableUnitSize(), AddressSpace.TYPE_STACK, 0);
// @formatter:off // @formatter:off

View file

@ -1,67 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.pcodeCPort.slgh_compile;
import static org.junit.Assert.*;
import java.io.*;
import java.util.List;
import org.junit.Test;
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
import ghidra.sleigh.grammar.Location;
import ghidra.test.AbstractGhidraHeadlessIntegrationTest;
public class PcodeParserTest extends AbstractGhidraHeadlessIntegrationTest {
private void compare(String actual, String expectedFilename) throws IOException {
List<String> expectedList = loadTextResource(getClass(), expectedFilename);
BufferedReader actualRdr = new BufferedReader(new StringReader(actual));
for (String expectedLine : expectedList) {
String actualLine = actualRdr.readLine();
assertEquals(expectedLine, actualLine);
}
assertNull(actualRdr.readLine());
}
@Test
public void testCompilePcode() throws Exception {
SleighLanguage lang = (SleighLanguage) getSLEIGH_X86_LANGUAGE();
long uniqueBase = 0x1000000; // make sure we avoid the decompiler range
String sleighSpec =
lang.buildTranslatorTag(lang.getAddressFactory(), uniqueBase, lang.getSymbolTable());
String pcodeStatements = "tmp:1 = inst_next;\n" + "if (AX == 0) goto inst_next;\n" +
"call [ECX];\n" + "if (BX != 1) goto <lab>;\n" + "CX = 0;\n" + "<lab>\n" +
"BX = CX << 2;\n" + "in1 = in2 + 7;";
PcodeParser parser = new PcodeParser(sleighSpec);
Location loc = new Location("pcodetest", 5);
parser.addOperand(loc, "in1", 0);
parser.addOperand(loc, "in2", 1);
String contructTplXml =
PcodeParser.stringifyTemplate(parser.compilePcode(pcodeStatements, "test", 200));
assertNotNull("Pcode compile failed (see log)", contructTplXml);
compare(contructTplXml, "pcode1.xml");
}
}

View file

@ -0,0 +1,252 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.program.model.lang;
import static org.junit.Assert.*;
import org.junit.Test;
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
import ghidra.app.plugin.processors.sleigh.UniqueLayout;
import ghidra.app.plugin.processors.sleigh.template.*;
import ghidra.program.model.pcode.PcodeOp;
import ghidra.sleigh.grammar.Location;
import ghidra.test.AbstractGhidraHeadlessIntegrationTest;
public class PcodeParserTest extends AbstractGhidraHeadlessIntegrationTest {
public boolean testVarnode(VarnodeTpl vn, String spaceName, long offset, int size) {
assertNotNull(vn);
if (vn.getSpace().getType() != ConstTpl.SPACEID) {
return false;
}
if (!vn.getSpace().getSpaceId().getName().equals(spaceName)) {
return false;
}
if (vn.getOffset().getType() != ConstTpl.REAL) {
return false;
}
if (vn.getOffset().getReal() != offset) {
return false;
}
if (vn.getSize().getType() != ConstTpl.REAL) {
return false;
}
if (vn.getSize().getReal() != size) {
return false;
}
return true;
}
public boolean testInstNextConstant(VarnodeTpl vn, int size) {
assertNotNull(vn);
if (vn.getSpace().getType() != ConstTpl.SPACEID) {
return false;
}
if (!vn.getSpace().getSpaceId().getName().equals(SpaceNames.CONSTANT_SPACE_NAME)) {
return false;
}
if (vn.getOffset().getType() != ConstTpl.J_NEXT) {
return false;
}
if (vn.getSize().getType() != ConstTpl.REAL) {
return false;
}
if (vn.getSize().getReal() != size) {
return false;
}
return true;
}
public boolean testInstNext(VarnodeTpl vn) {
assertNotNull(vn);
if (vn.getSpace().getType() != ConstTpl.J_CURSPACE) {
return false;
}
if (vn.getOffset().getType() != ConstTpl.J_NEXT) {
return false;
}
if (vn.getSize().getType() != ConstTpl.J_CURSPACE_SIZE) {
return false;
}
return true;
}
public boolean testRelative(VarnodeTpl vn, int labelid, int size) {
assertNotNull(vn);
if (vn.getSpace().getType() != ConstTpl.SPACEID) {
return false;
}
if (!vn.getSpace().getSpaceId().getName().equals(SpaceNames.CONSTANT_SPACE_NAME)) {
return false;
}
if (vn.getOffset().getType() != ConstTpl.J_RELATIVE) {
return false;
}
if (vn.getOffset().getReal() != labelid) {
return false;
}
if (vn.getSize().getType() != ConstTpl.REAL) {
return false;
}
if (vn.getSize().getReal() != size) {
return false;
}
return true;
}
public boolean testParameter(VarnodeTpl vn, int paramnum) {
assertNotNull(vn);
if (vn.getSpace().getType() != ConstTpl.HANDLE) {
return false;
}
if (vn.getSpace().getHandleIndex() != paramnum) {
return false;
}
if (vn.getSpace().getSelect() != ConstTpl.V_SPACE) {
return false;
}
if (vn.getOffset().getType() != ConstTpl.HANDLE) {
return false;
}
if (vn.getOffset().getHandleIndex() != paramnum) {
return false;
}
if (vn.getOffset().getSelect() != ConstTpl.V_OFFSET) {
return false;
}
if (vn.getSize().getType() != ConstTpl.HANDLE) {
return false;
}
if (vn.getSize().getHandleIndex() != paramnum) {
return false;
}
if (vn.getSize().getSelect() != ConstTpl.V_SIZE) {
return false;
}
return true;
}
public boolean testVarnodeHandleSize(VarnodeTpl vn, String spaceName, long offset,
int paramnum) {
assertNotNull(vn);
if (vn.getSpace().getType() != ConstTpl.SPACEID) {
return false;
}
if (!vn.getSpace().getSpaceId().getName().equals(spaceName)) {
return false;
}
if (vn.getOffset().getType() != ConstTpl.REAL) {
return false;
}
if (vn.getOffset().getReal() != offset) {
return false;
}
if (vn.getSize().getType() != ConstTpl.HANDLE) {
return false;
}
if (vn.getSize().getHandleIndex() != paramnum) {
return false;
}
if (vn.getSize().getSelect() != ConstTpl.V_SIZE) {
return false;
}
return true;
}
@Test
public void testCompilePcode() throws Exception {
SleighLanguage lang = (SleighLanguage) getSLEIGH_X86_LANGUAGE();
long uniqueBase = UniqueLayout.INJECT.getOffset(lang);
String pcodeStatements = "tmp:1 = inst_next;\n" + "if (AX == 0) goto inst_next;\n" +
"call [ECX];\n" + "if (BX != 1) goto <lab>;\n" + "CX = 0;\n" + "<lab>\n" +
"BX = CX << 2;\n" + "in1 = in2 + 7;";
PcodeParser parser = new PcodeParser(lang, uniqueBase);
Location loc = new Location("pcodetest", 5);
parser.addOperand(loc, "in1", 0);
parser.addOperand(loc, "in2", 1);
ConstructTpl template = parser.compilePcode(pcodeStatements, "test", 200);
assertNull(template.getResult());
assertEquals(template.getNumLabels(), 1);
OpTpl[] vec = template.getOpVec();
assertEquals(vec.length, 10);
assertEquals(vec[0].getOpcode(), PcodeOp.COPY);
assertTrue(testVarnode(vec[0].getOutput(), SpaceNames.UNIQUE_SPACE_NAME, uniqueBase, 1));
assertEquals(vec[0].getInput().length, 1);
assertTrue(testInstNextConstant(vec[0].getInput()[0], 1));
assertEquals(vec[1].getOpcode(), PcodeOp.INT_EQUAL);
assertTrue(
testVarnode(vec[1].getOutput(), SpaceNames.UNIQUE_SPACE_NAME, uniqueBase + 0x80, 1));
assertEquals(vec[1].getInput().length, 2);
assertTrue(testVarnode(vec[1].getInput()[0], "register", 0, 2));
assertTrue(testVarnode(vec[1].getInput()[1], SpaceNames.CONSTANT_SPACE_NAME, 0, 2));
assertEquals(vec[2].getOpcode(), PcodeOp.CBRANCH);
assertNull(vec[2].getOutput());
assertEquals(vec[2].getInput().length, 2);
assertTrue(testInstNext(vec[2].getInput()[0]));
assertTrue(
testVarnode(vec[2].getInput()[1], SpaceNames.UNIQUE_SPACE_NAME, uniqueBase + 0x80, 1));
assertEquals(vec[3].getOpcode(), PcodeOp.CALLIND);
assertNull(vec[3].getOutput());
assertEquals(vec[3].getInput().length, 1);
assertTrue(testVarnode(vec[3].getInput()[0], "register", 4, 4));
assertEquals(vec[4].getOpcode(), PcodeOp.INT_NOTEQUAL);
assertTrue(
testVarnode(vec[4].getOutput(), SpaceNames.UNIQUE_SPACE_NAME, uniqueBase + 0x100, 1));
assertEquals(vec[4].getInput().length, 2);
assertTrue(testVarnode(vec[4].getInput()[0], "register", 0xc, 2));
assertTrue(testVarnode(vec[4].getInput()[1], SpaceNames.CONSTANT_SPACE_NAME, 1, 2));
assertEquals(vec[5].getOpcode(), PcodeOp.CBRANCH);
assertNull(vec[5].getOutput());
assertEquals(vec[5].getInput().length, 2);
assertTrue(testRelative(vec[5].getInput()[0], 0, 4));
assertTrue(
testVarnode(vec[5].getInput()[1], SpaceNames.UNIQUE_SPACE_NAME, uniqueBase + 0x100, 1));
assertEquals(vec[6].getOpcode(), PcodeOp.COPY);
assertTrue(testVarnode(vec[6].getOutput(), "register", 4, 2));
assertEquals(vec[6].getInput().length, 1);
assertTrue(testVarnode(vec[6].getInput()[0], SpaceNames.CONSTANT_SPACE_NAME, 0, 2));
assertEquals(vec[7].getOpcode(), PcodeOp.PTRADD); // label
assertNull(vec[7].getOutput());
assertEquals(vec[7].getInput().length, 1);
assertTrue(testVarnode(vec[7].getInput()[0], SpaceNames.CONSTANT_SPACE_NAME, 0, 4));
assertEquals(vec[8].getOpcode(), PcodeOp.INT_LEFT);
assertTrue(testVarnode(vec[8].getOutput(), "register", 0xc, 2));
assertEquals(vec[8].getInput().length, 2);
assertTrue(testVarnode(vec[8].getInput()[0], "register", 0x4, 2));
assertTrue(testVarnode(vec[8].getInput()[1], SpaceNames.CONSTANT_SPACE_NAME, 2, 4));
assertEquals(vec[9].getOpcode(), PcodeOp.INT_ADD);
assertTrue(testParameter(vec[9].getOutput(), 0));
assertEquals(vec[9].getInput().length, 2);
assertTrue(testParameter(vec[9].getInput()[0], 1));
assertTrue(
testVarnodeHandleSize(vec[9].getInput()[1], SpaceNames.CONSTANT_SPACE_NAME, 7, 0));
}
}

View file

@ -1,38 +0,0 @@
<construct_tpl labels="1">
<null/><op_tpl code="COPY"><varnode_tpl><const_tpl type="spaceid" name="unique"/><const_tpl type="real" val="0x1000000"/><const_tpl type="real" val="0x1"/></varnode_tpl>
<varnode_tpl><const_tpl type="spaceid" name="const"/><const_tpl type="next"/><const_tpl type="real" val="0x1"/></varnode_tpl>
</op_tpl>
<op_tpl code="INT_EQUAL"><varnode_tpl><const_tpl type="spaceid" name="unique"/><const_tpl type="real" val="0x1000080"/><const_tpl type="real" val="0x1"/></varnode_tpl>
<varnode_tpl><const_tpl type="spaceid" name="register"/><const_tpl type="real" val="0x0"/><const_tpl type="real" val="0x2"/></varnode_tpl>
<varnode_tpl><const_tpl type="spaceid" name="const"/><const_tpl type="real" val="0x0"/><const_tpl type="real" val="0x2"/></varnode_tpl>
</op_tpl>
<op_tpl code="CBRANCH"><null/>
<varnode_tpl><const_tpl type="curspace"/><const_tpl type="next"/><const_tpl type="curspace_size"/></varnode_tpl>
<varnode_tpl><const_tpl type="spaceid" name="unique"/><const_tpl type="real" val="0x1000080"/><const_tpl type="real" val="0x1"/></varnode_tpl>
</op_tpl>
<op_tpl code="CALLIND"><null/>
<varnode_tpl><const_tpl type="spaceid" name="register"/><const_tpl type="real" val="0x4"/><const_tpl type="real" val="0x4"/></varnode_tpl>
</op_tpl>
<op_tpl code="INT_NOTEQUAL"><varnode_tpl><const_tpl type="spaceid" name="unique"/><const_tpl type="real" val="0x1000100"/><const_tpl type="real" val="0x1"/></varnode_tpl>
<varnode_tpl><const_tpl type="spaceid" name="register"/><const_tpl type="real" val="0xc"/><const_tpl type="real" val="0x2"/></varnode_tpl>
<varnode_tpl><const_tpl type="spaceid" name="const"/><const_tpl type="real" val="0x1"/><const_tpl type="real" val="0x2"/></varnode_tpl>
</op_tpl>
<op_tpl code="CBRANCH"><null/>
<varnode_tpl><const_tpl type="spaceid" name="const"/><const_tpl type="relative" val="0x0"/><const_tpl type="real" val="0x4"/></varnode_tpl>
<varnode_tpl><const_tpl type="spaceid" name="unique"/><const_tpl type="real" val="0x1000100"/><const_tpl type="real" val="0x1"/></varnode_tpl>
</op_tpl>
<op_tpl code="COPY"><varnode_tpl><const_tpl type="spaceid" name="register"/><const_tpl type="real" val="0x4"/><const_tpl type="real" val="0x2"/></varnode_tpl>
<varnode_tpl><const_tpl type="spaceid" name="const"/><const_tpl type="real" val="0x0"/><const_tpl type="real" val="0x2"/></varnode_tpl>
</op_tpl>
<op_tpl code="LABEL"><null/>
<varnode_tpl><const_tpl type="spaceid" name="const"/><const_tpl type="real" val="0x0"/><const_tpl type="real" val="0x4"/></varnode_tpl>
</op_tpl>
<op_tpl code="INT_LEFT"><varnode_tpl><const_tpl type="spaceid" name="register"/><const_tpl type="real" val="0xc"/><const_tpl type="real" val="0x2"/></varnode_tpl>
<varnode_tpl><const_tpl type="spaceid" name="register"/><const_tpl type="real" val="0x4"/><const_tpl type="real" val="0x2"/></varnode_tpl>
<varnode_tpl><const_tpl type="spaceid" name="const"/><const_tpl type="real" val="0x2"/><const_tpl type="real" val="0x4"/></varnode_tpl>
</op_tpl>
<op_tpl code="INT_ADD"><varnode_tpl><const_tpl type="handle" val="0" s="space"/><const_tpl type="handle" val="0" s="offset"/><const_tpl type="handle" val="0" s="size"/></varnode_tpl>
<varnode_tpl><const_tpl type="handle" val="1" s="space"/><const_tpl type="handle" val="1" s="offset"/><const_tpl type="handle" val="1" s="size"/></varnode_tpl>
<varnode_tpl><const_tpl type="spaceid" name="const"/><const_tpl type="real" val="0x7"/><const_tpl type="handle" val="0" s="size"/></varnode_tpl>
</op_tpl>
</construct_tpl>