GT-2816 added ability to override indirect call destinations

This commit is contained in:
James 2019-04-17 13:34:29 -04:00
parent 4ce178c419
commit fa14932797
5 changed files with 229 additions and 179 deletions

View File

@ -149,7 +149,7 @@ public abstract class PcodeEmit {
public ParserWalker getWalker() { public ParserWalker getWalker() {
return walker; return walker;
} }
/** /**
* Make a note of the current op index, and associate * Make a note of the current op index, and associate
* it with the label index from the label template, * it with the label index from the label template,
@ -158,11 +158,13 @@ public abstract class PcodeEmit {
* @param op = the label template op * @param op = the label template op
*/ */
private void setLabel(OpTpl op) { private void setLabel(OpTpl op) {
if (labeldef == null) if (labeldef == null) {
labeldef = new ArrayList<Integer>(); labeldef = new ArrayList<Integer>();
}
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) {
labeldef.add(null); labeldef.add(null);
}
labeldef.set(labelindex, numOps); labeldef.set(labelindex, numOps);
} }
@ -205,8 +207,8 @@ public abstract class PcodeEmit {
private void dumpNullReturn() { private void dumpNullReturn() {
VarnodeTpl nullAddr = VarnodeTpl nullAddr =
new VarnodeTpl(new ConstTpl(const_space), new ConstTpl(ConstTpl.REAL, 0), new ConstTpl( new VarnodeTpl(new ConstTpl(const_space), new ConstTpl(ConstTpl.REAL, 0),
ConstTpl.REAL, const_space.getPointerSize())); new ConstTpl(ConstTpl.REAL, const_space.getPointerSize()));
OpTpl retOpt = new OpTpl(PcodeOp.RETURN, null, new VarnodeTpl[] { nullAddr }); OpTpl retOpt = new OpTpl(PcodeOp.RETURN, null, new VarnodeTpl[] { nullAddr });
dump(retOpt); dump(retOpt);
@ -253,13 +255,11 @@ public abstract class PcodeEmit {
// <label> // <label>
Address tmpAddr = uniqueFactory.getNextUniqueAddress(); Address tmpAddr = uniqueFactory.getNextUniqueAddress();
VarnodeTpl tmp = VarnodeTpl tmp = new VarnodeTpl(new ConstTpl(tmpAddr.getAddressSpace()),
new VarnodeTpl(new ConstTpl(tmpAddr.getAddressSpace()), new ConstTpl(ConstTpl.REAL, new ConstTpl(ConstTpl.REAL, tmpAddr.getOffset()), inputs[1].getSize());
tmpAddr.getOffset()), inputs[1].getSize());
int labelIndex = labelcount++; int labelIndex = labelcount++;
VarnodeTpl label = VarnodeTpl label = new VarnodeTpl(new ConstTpl(const_space),
new VarnodeTpl(new ConstTpl(const_space), new ConstTpl(ConstTpl.J_RELATIVE, new ConstTpl(ConstTpl.J_RELATIVE, labelIndex), new ConstTpl(ConstTpl.REAL, 8));
labelIndex), new ConstTpl(ConstTpl.REAL, 8));
VarnodeTpl dest = inputs[0]; VarnodeTpl dest = inputs[0];
VarnodeTpl cond = inputs[1]; VarnodeTpl cond = inputs[1];
@ -311,13 +311,12 @@ public abstract class PcodeEmit {
// RETURN tmp // RETURN tmp
Address tmpAddr = uniqueFactory.getNextUniqueAddress(); Address tmpAddr = uniqueFactory.getNextUniqueAddress();
VarnodeTpl tmp = VarnodeTpl tmp = new VarnodeTpl(new ConstTpl(tmpAddr.getAddressSpace()),
new VarnodeTpl(new ConstTpl(tmpAddr.getAddressSpace()), new ConstTpl(ConstTpl.REAL, new ConstTpl(ConstTpl.REAL, tmpAddr.getOffset()),
tmpAddr.getOffset()), new ConstTpl(ConstTpl.REAL, ptrSize)); new ConstTpl(ConstTpl.REAL, ptrSize));
VarnodeTpl destAddr = VarnodeTpl destAddr = new VarnodeTpl(new ConstTpl(const_space), inputs[0].getOffset(),
new VarnodeTpl(new ConstTpl(const_space), inputs[0].getOffset(), new ConstTpl( new ConstTpl(ConstTpl.REAL, ptrSize));
ConstTpl.REAL, ptrSize));
OpTpl copyOpt = new OpTpl(PcodeOp.COPY, tmp, new VarnodeTpl[] { destAddr }); OpTpl copyOpt = new OpTpl(PcodeOp.COPY, tmp, new VarnodeTpl[] { destAddr });
dump(copyOpt); dump(copyOpt);
@ -353,23 +352,20 @@ public abstract class PcodeEmit {
// <label> // <label>
Address tmpAddr = uniqueFactory.getNextUniqueAddress(); Address tmpAddr = uniqueFactory.getNextUniqueAddress();
VarnodeTpl tmp = VarnodeTpl tmp = new VarnodeTpl(new ConstTpl(tmpAddr.getAddressSpace()),
new VarnodeTpl(new ConstTpl(tmpAddr.getAddressSpace()), new ConstTpl(ConstTpl.REAL, new ConstTpl(ConstTpl.REAL, tmpAddr.getOffset()), inputs[1].getSize());
tmpAddr.getOffset()), inputs[1].getSize());
tmpAddr = uniqueFactory.getNextUniqueAddress(); tmpAddr = uniqueFactory.getNextUniqueAddress();
VarnodeTpl tmp2 = VarnodeTpl tmp2 = new VarnodeTpl(new ConstTpl(tmpAddr.getAddressSpace()),
new VarnodeTpl(new ConstTpl(tmpAddr.getAddressSpace()), new ConstTpl(ConstTpl.REAL, new ConstTpl(ConstTpl.REAL, tmpAddr.getOffset()),
tmpAddr.getOffset()), new ConstTpl(ConstTpl.REAL, ptrSize)); new ConstTpl(ConstTpl.REAL, ptrSize));
VarnodeTpl destAddr = VarnodeTpl destAddr = new VarnodeTpl(new ConstTpl(const_space), inputs[0].getOffset(),
new VarnodeTpl(new ConstTpl(const_space), inputs[0].getOffset(), new ConstTpl( new ConstTpl(ConstTpl.REAL, ptrSize));
ConstTpl.REAL, ptrSize));
int labelIndex = labelcount++; int labelIndex = labelcount++;
VarnodeTpl label = VarnodeTpl label = new VarnodeTpl(new ConstTpl(const_space),
new VarnodeTpl(new ConstTpl(const_space), new ConstTpl(ConstTpl.J_RELATIVE, new ConstTpl(ConstTpl.J_RELATIVE, labelIndex), new ConstTpl(ConstTpl.REAL, 8));
labelIndex), new ConstTpl(ConstTpl.REAL, 8));
VarnodeTpl cond = inputs[1]; VarnodeTpl cond = inputs[1];
OpTpl negOpt = new OpTpl(PcodeOp.BOOL_NEGATE, tmp, new VarnodeTpl[] { cond }); OpTpl negOpt = new OpTpl(PcodeOp.BOOL_NEGATE, tmp, new VarnodeTpl[] { cond });
@ -420,13 +416,16 @@ public abstract class PcodeEmit {
private void generateLocation(VarnodeTpl vntpl, VarnodeData vn) { private void generateLocation(VarnodeTpl vntpl, VarnodeData vn) {
vn.space = vntpl.getSpace().fixSpace(walker); vn.space = vntpl.getSpace().fixSpace(walker);
vn.size = (int) vntpl.getSize().fix(walker); vn.size = (int) vntpl.getSize().fix(walker);
if (vn.space == const_space) if (vn.space == const_space) {
vn.offset = vn.offset =
vntpl.getOffset().fix(walker) & ConstTpl.calc_mask[vn.size > 8 ? 8 : vn.size]; vntpl.getOffset().fix(walker) & ConstTpl.calc_mask[vn.size > 8 ? 8 : vn.size];
else if (vn.space == uniq_space) }
else if (vn.space == uniq_space) {
vn.offset = vntpl.getOffset().fix(walker) | uniqueoffset; vn.offset = vntpl.getOffset().fix(walker) | uniqueoffset;
else }
else {
vn.offset = vn.space.truncateOffset(vntpl.getOffset().fix(walker)); vn.offset = vn.space.truncateOffset(vntpl.getOffset().fix(walker));
}
} }
/** /**
@ -439,12 +438,15 @@ public abstract class PcodeEmit {
FixedHandle hand = walker.getFixedHandle(vntpl.getOffset().getHandleIndex()); FixedHandle hand = walker.getFixedHandle(vntpl.getOffset().getHandleIndex());
vn.space = hand.offset_space; vn.space = hand.offset_space;
vn.size = hand.offset_size; vn.size = hand.offset_size;
if (vn.space == const_space) if (vn.space == const_space) {
vn.offset = hand.offset_offset & ConstTpl.calc_mask[vn.size]; vn.offset = hand.offset_offset & ConstTpl.calc_mask[vn.size];
else if (vn.space == uniq_space) }
else if (vn.space == uniq_space) {
vn.offset = hand.offset_offset | uniqueoffset; vn.offset = hand.offset_offset | uniqueoffset;
else }
else {
vn.offset = vn.space.truncateOffset(hand.offset_offset); vn.offset = vn.space.truncateOffset(hand.offset_offset);
}
return hand.space; return hand.space;
} }
@ -473,8 +475,9 @@ public abstract class PcodeEmit {
dump(startAddress, PcodeOp.LOAD, dyncache, 2, dyncache[2]); dump(startAddress, PcodeOp.LOAD, dyncache, 2, dyncache[2]);
numOps += 1; numOps += 1;
} }
else else {
generateLocation(vn, incache[i]); generateLocation(vn, incache[i]);
}
} }
if ((isize > 0) && (opt.getInput()[0].isRelative())) { if ((isize > 0) && (opt.getInput()[0].isRelative())) {
incache[0].offset += labelbase; incache[0].offset += labelbase;
@ -515,22 +518,25 @@ public abstract class PcodeEmit {
} }
} }
private void appendBuild(OpTpl bld, int secnum) throws UnknownInstructionException, private void appendBuild(OpTpl bld, int secnum)
MemoryAccessException { throws UnknownInstructionException, MemoryAccessException {
// Recover operand index from build statement // Recover operand index from build statement
int index = (int) bld.getInput()[0].getOffset().getReal(); int index = (int) bld.getInput()[0].getOffset().getReal();
Symbol sym = walker.getConstructor().getOperand(index).getDefiningSymbol(); Symbol sym = walker.getConstructor().getOperand(index).getDefiningSymbol();
if ((sym == null) || (!(sym instanceof SubtableSymbol))) if ((sym == null) || (!(sym instanceof SubtableSymbol))) {
return; return;
}
walker.pushOperand(index); walker.pushOperand(index);
Constructor ct = walker.getConstructor(); Constructor ct = walker.getConstructor();
if (secnum >= 0) { if (secnum >= 0) {
ConstructTpl construct = ct.getNamedTempl(secnum); ConstructTpl construct = ct.getNamedTempl(secnum);
if (construct == null) if (construct == null) {
buildEmpty(ct, secnum); buildEmpty(ct, secnum);
else }
else {
build(construct, secnum); build(construct, secnum);
}
} }
else { else {
ConstructTpl construct = ct.getTempl(); ConstructTpl construct = ct.getTempl();
@ -548,8 +554,8 @@ public abstract class PcodeEmit {
private void delaySlot(OpTpl op) throws UnknownInstructionException, MemoryAccessException { private void delaySlot(OpTpl op) throws UnknownInstructionException, MemoryAccessException {
if (inDelaySlot) { if (inDelaySlot) {
throw new SleighException("Delay Slot recursion problem for Instruction at " + throw new SleighException(
walker.getAddr()); "Delay Slot recursion problem for Instruction at " + walker.getAddr());
} }
inDelaySlot = true; inDelaySlot = true;
Address baseaddr = parsercontext.getAddr(); Address baseaddr = parsercontext.getAddr();
@ -589,11 +595,12 @@ public abstract class PcodeEmit {
* @throws UnknownInstructionException * @throws UnknownInstructionException
* @throws MemoryAccessException * @throws MemoryAccessException
*/ */
private void appendCrossBuild(OpTpl bld, int secnum) throws UnknownInstructionException, private void appendCrossBuild(OpTpl bld, int secnum)
MemoryAccessException { throws UnknownInstructionException, MemoryAccessException {
if (secnum >= 0) if (secnum >= 0) {
throw new SleighException("CROSSBUILD recursion problem for instruction at " + throw new SleighException(
walker.getAddr()); "CROSSBUILD recursion problem for instruction at " + walker.getAddr());
}
secnum = (int) bld.getInput()[1].getOffset().getReal(); secnum = (int) bld.getInput()[1].getOffset().getReal();
VarnodeTpl vn = bld.getInput()[0]; VarnodeTpl vn = bld.getInput()[0];
AddressSpace spc = vn.getSpace().fixSpace(walker); AddressSpace spc = vn.getSpace().fixSpace(walker);
@ -609,35 +616,38 @@ public abstract class PcodeEmit {
parsercontext = (SleighParserContext) instcontext.getParserContext(addr); parsercontext = (SleighParserContext) instcontext.getParserContext(addr);
} }
catch (UnknownContextException e) { catch (UnknownContextException e) {
throw new UnknownInstructionException("Could not find cached crossbuild parser context"); throw new UnknownInstructionException(
"Could not find cached crossbuild parser context");
} }
walker = new ParserWalker(parsercontext, oldwalker.getParserContext()); walker = new ParserWalker(parsercontext, oldwalker.getParserContext());
walker.baseState(); walker.baseState();
Constructor ct = walker.getConstructor(); Constructor ct = walker.getConstructor();
ConstructTpl construct = ct.getNamedTempl(secnum); ConstructTpl construct = ct.getNamedTempl(secnum);
if (construct == null) if (construct == null) {
buildEmpty(ct, secnum); buildEmpty(ct, secnum);
else }
else {
build(construct, secnum); build(construct, secnum);
}
walker = oldwalker; walker = oldwalker;
parsercontext = walker.getParserContext(); parsercontext = walker.getParserContext();
uniqueoffset = olduniqueoffset; uniqueoffset = olduniqueoffset;
} }
public void build(ConstructTpl construct, int secnum) throws UnknownInstructionException, public void build(ConstructTpl construct, int secnum)
MemoryAccessException { throws UnknownInstructionException, MemoryAccessException {
if (construct == null) if (construct == null) {
throw new NotYetImplementedException( throw new NotYetImplementedException(
"Semantics for this instruction are not implemented"); "Semantics for this instruction are not implemented");
}
int oldbase = labelbase; // Recursively save old labelbase int oldbase = labelbase; // Recursively save old labelbase
labelbase = labelcount; labelbase = labelcount;
labelcount += construct.getNumLabels(); labelcount += construct.getNumLabels();
OpTpl[] optpllist = construct.getOpVec(); OpTpl[] optpllist = construct.getOpVec();
for (int i = 0; i < optpllist.length; ++i) { for (OpTpl op : optpllist) {
OpTpl op = optpllist[i];
switch (op.getOpcode()) { switch (op.getOpcode()) {
case PcodeOp.MULTIEQUAL: // Build placeholder case PcodeOp.MULTIEQUAL: // Build placeholder
appendBuild(op, secnum); appendBuild(op, secnum);
@ -668,28 +678,32 @@ public abstract class PcodeEmit {
* @throws MemoryAccessException * @throws MemoryAccessException
* @throws UnknownInstructionException * @throws UnknownInstructionException
*/ */
private void buildEmpty(Constructor ct, int secnum) throws UnknownInstructionException, private void buildEmpty(Constructor ct, int secnum)
MemoryAccessException { throws UnknownInstructionException, MemoryAccessException {
int numops = ct.getNumOperands(); int numops = ct.getNumOperands();
for (int i = 0; i < numops; ++i) { for (int i = 0; i < numops; ++i) {
TripleSymbol sym = ct.getOperand(i).getDefiningSymbol(); TripleSymbol sym = ct.getOperand(i).getDefiningSymbol();
if ((sym == null) || (!(sym instanceof SubtableSymbol))) if ((sym == null) || (!(sym instanceof SubtableSymbol))) {
continue; continue;
}
walker.pushOperand(i); walker.pushOperand(i);
ConstructTpl construct = walker.getConstructor().getNamedTempl(secnum); ConstructTpl construct = walker.getConstructor().getNamedTempl(secnum);
if (construct == null) if (construct == null) {
buildEmpty(walker.getConstructor(), secnum); buildEmpty(walker.getConstructor(), secnum);
else }
else {
build(construct, secnum); build(construct, secnum);
}
walker.popOperand(); walker.popOperand();
} }
} }
void checkOverlays(int opcode, VarnodeData[] in, int isize, VarnodeData out) { void checkOverlays(int opcode, VarnodeData[] in, int isize, VarnodeData out) {
if (uniqueFactory == null) if (uniqueFactory == null) {
return; 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 = uniqueFactory.getAddressFactory().getAddressSpace(spaceId);
@ -713,16 +727,36 @@ public abstract class PcodeEmit {
} }
} }
void checkOverrides(int opcode, VarnodeData[] in) { /**
* Applies opcode-specific overrides
* @param opcode opcode of instruction
* @param in input varnodes
* @return opcode of modified instruction
*/
int checkOverrides(int opcode, VarnodeData[] in) {
if (override == null) { if (override == null) {
return; return opcode;
}
//If there is an overriding reference on an indirect call, change the indirect
//call to a direct call
if (opcode == PcodeOp.CALLIND) {
Address callRef = override.getOverridingCallReference();
if (callRef != null) {
VarnodeData dest = in[0];
dest.space = callRef.getAddressSpace();
dest.offset = callRef.getOffset();
dest.size = dest.space.getPointerSize();
return PcodeOp.CALL;
}
} }
// Simple call reference override - use primary call reference as destination // Simple call reference override - use primary call reference as destination
// Only perform reference override if destination function does not have a call-fixup // Only perform reference override if destination function does not have a call-fixup
if (opcode == PcodeOp.CALL && !override.hasCallFixup(in[0].space.getAddress(in[0].offset))) { if (opcode == PcodeOp.CALL &&
!override.hasCallFixup(in[0].space.getAddress(in[0].offset))) {
// Check for call reference (not supported if call-fixup exists for the instruction) // Check for call reference (not supported if call-fixup exists for the instruction)
Address callRef = override.getPrimaryCallReference(); Address callRef = override.getOverridingCallReference();
if (callRef != null) { if (callRef != null) {
VarnodeData dest = in[0]; VarnodeData dest = in[0];
dest.space = callRef.getAddressSpace(); dest.space = callRef.getAddressSpace();
@ -740,6 +774,6 @@ public abstract class PcodeEmit {
dest.size = dest.space.getPointerSize(); dest.size = dest.space.getPointerSize();
} }
} }
return opcode;
} }
} }

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,40 +15,36 @@
*/ */
package ghidra.app.plugin.processors.sleigh; package ghidra.app.plugin.processors.sleigh;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSpace;
import ghidra.program.model.address.UniqueAddressFactory;
import ghidra.program.model.lang.InstructionContext;
import ghidra.program.model.pcode.PcodeOp;
import ghidra.program.model.pcode.PcodeOverride;
import ghidra.program.model.pcode.Varnode;
import java.util.ArrayList; import java.util.ArrayList;
import ghidra.program.model.address.*;
import ghidra.program.model.lang.InstructionContext;
import ghidra.program.model.pcode.*;
public class PcodeEmitObjects extends PcodeEmit { public class PcodeEmitObjects extends PcodeEmit {
private ArrayList<PcodeOp> oplist; private ArrayList<PcodeOp> oplist;
private ArrayList<Integer> labelref = null; private ArrayList<Integer> labelref = null;
/** /**
* Pcode emitter constructor for producing PcodeOp objects for unimplemented, snippets or empty responses * Pcode emitter constructor for producing PcodeOp objects for unimplemented, snippets or empty responses
* when {@link #getFallOffset()} will not be used. * when {@link #getFallOffset()} will not be used.
* @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, null);
} }
/** /**
* Pcode emitter constructor for producing PcodeOp objects for unimplemented, snippets or empty responses. * Pcode emitter constructor for producing PcodeOp objects for unimplemented, snippets or empty responses.
* @param walk state of the ParserContext from which to generate p-code * @param walk state of the ParserContext from which to generate p-code
* @param fallOffset default fall-through offset (i.e., the full length * @param fallOffset default fall-through offset (i.e., the full length
* 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, null);
} }
/** /**
* @param walk state of the ParserContext from which to generate p-code * @param walk state of the ParserContext from which to generate p-code
* @param ictx is the InstructionContext used to resolve delayslot and crossbuild directives * @param ictx is the InstructionContext used to resolve delayslot and crossbuild directives
@ -57,68 +52,76 @@ public class PcodeEmitObjects extends PcodeEmit {
* @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 * @param uniqueFactory required when override specified or if overlay normalization is required
*/ */
public PcodeEmitObjects(ParserWalker walk,InstructionContext ictx, int fallOffset, PcodeOverride override, UniqueAddressFactory uniqueFactory) { public PcodeEmitObjects(ParserWalker walk, InstructionContext ictx, int fallOffset,
super(walk,ictx,fallOffset,override,uniqueFactory); PcodeOverride override, UniqueAddressFactory uniqueFactory) {
super(walk, ictx, fallOffset, override, uniqueFactory);
oplist = new ArrayList<PcodeOp>(); oplist = new ArrayList<PcodeOp>();
} }
public PcodeOp[] getPcodeOp() { public PcodeOp[] getPcodeOp() {
PcodeOp[] retop = new PcodeOp[oplist.size()]; PcodeOp[] retop = new PcodeOp[oplist.size()];
oplist.toArray(retop); oplist.toArray(retop);
return retop; return retop;
} }
/* (non-Javadoc) /* (non-Javadoc)
* @see ghidra.app.plugin.processors.sleigh.PcodeEmit#resolveRelatives() * @see ghidra.app.plugin.processors.sleigh.PcodeEmit#resolveRelatives()
*/ */
@Override
public void resolveRelatives() { public void resolveRelatives() {
if (labelref==null) return; if (labelref == null) {
for(int i=0;i<labelref.size();++i) { return;
}
for (int i = 0; i < labelref.size(); ++i) {
int opindex = labelref.get(i); 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();
if ((labelid>=labeldef.size())||(labeldef.get(labelid)==null)) if ((labelid >= labeldef.size()) || (labeldef.get(labelid) == null)) {
throw new SleighException("Reference to non-existant sleigh label"); throw new SleighException("Reference to non-existant sleigh label");
long res = (long)labeldef.get(labelid) - (long)opindex; }
long res = (long) labeldef.get(labelid) - (long) opindex;
if (vn.getSize() < 8) { if (vn.getSize() < 8) {
long mask = -1; long mask = -1;
mask >>>= (8-vn.getSize())*8; mask >>>= (8 - vn.getSize()) * 8;
res &= mask; res &= mask;
} }
AddressSpace spc = vn.getAddress().getAddressSpace(); AddressSpace spc = vn.getAddress().getAddressSpace();
vn = new Varnode(spc.getAddress(res),vn.getSize()); vn = new Varnode(spc.getAddress(res), vn.getSize());
op.setInput(vn, 0); op.setInput(vn, 0);
} }
} }
/* (non-Javadoc) /* (non-Javadoc)
* @see ghidra.app.plugin.processors.sleigh.PcodeEmit#addLabelRef() * @see ghidra.app.plugin.processors.sleigh.PcodeEmit#addLabelRef()
*/ */
@Override
void addLabelRef() { void addLabelRef() {
if (labelref == null) if (labelref == null) {
labelref = new ArrayList<Integer>(); labelref = new ArrayList<Integer>();
}
labelref.add(numOps); labelref.add(numOps);
} }
/* (non-Javadoc) /* (non-Javadoc)
* @see ghidra.app.plugin.processors.sleigh.PcodeEmit#dump(ghidra.program.model.address.Address, int, ghidra.app.plugin.processors.sleigh.VarnodeData[], int, ghidra.app.plugin.processors.sleigh.VarnodeData) * @see ghidra.app.plugin.processors.sleigh.PcodeEmit#dump(ghidra.program.model.address.Address, int, ghidra.app.plugin.processors.sleigh.VarnodeData[], int, ghidra.app.plugin.processors.sleigh.VarnodeData)
*/ */
void dump(Address instrAddr, int opcode,VarnodeData[] in,int isize,VarnodeData out) { @Override
checkOverrides(opcode,in); void dump(Address instrAddr, int opcode, VarnodeData[] in, int isize, VarnodeData out) {
opcode = checkOverrides(opcode, in);
Varnode outvn; Varnode outvn;
if (out != null) { if (out != null) {
outvn = new Varnode(out.space.getAddress(out.offset),out.size); outvn = new Varnode(out.space.getAddress(out.offset), out.size);
} }
else else {
outvn = null; outvn = null;
Varnode[] invn = new Varnode[isize];
for(int i=0;i<isize;++i) {
invn[i] = new Varnode(in[i].space.getAddress(in[i].offset),
in[i].size);
} }
PcodeOp op = new PcodeOp(instrAddr,oplist.size(), opcode,invn,outvn); Varnode[] invn = new Varnode[isize];
for (int i = 0; i < isize; ++i) {
invn[i] = new Varnode(in[i].space.getAddress(in[i].offset), in[i].size);
}
PcodeOp op = new PcodeOp(instrAddr, oplist.size(), opcode, invn, outvn);
oplist.add(op); oplist.add(op);
} }
} }

View File

@ -28,30 +28,26 @@ import ghidra.program.model.pcode.PcodeOverride;
* *
*/ */
public class PcodeEmitPacked extends PcodeEmit { public class PcodeEmitPacked extends PcodeEmit {
public final static int unimpl_tag = 0x20, public final static int unimpl_tag = 0x20, inst_tag = 0x21, op_tag = 0x22, void_tag = 0x23,
inst_tag = 0x21, spaceid_tag = 0x24, addrsz_tag = 0x25, end_tag = 0x60; // End of a number
op_tag = 0x22,
void_tag = 0x23,
spaceid_tag = 0x24,
addrsz_tag = 0x25,
end_tag = 0x60; // End of a number
public class LabelRef { public class LabelRef {
public int opIndex; // Index of operation referencing the label public int opIndex; // Index of operation referencing the label
public int labelIndex; // Index of label being referenced public int labelIndex; // Index of label being referenced
public int labelSize; // Number of bytes in the label public int labelSize; // Number of bytes in the label
public int streampos; // Position in byte stream where label is getting encoded public int streampos; // Position in byte stream where label is getting encoded
public LabelRef(int op,int lab,int size,int stream) {
public LabelRef(int op, int lab, int size, int stream) {
opIndex = op; opIndex = op;
labelIndex = lab; labelIndex = lab;
labelSize = size; labelSize = size;
streampos = stream; streampos = stream;
} }
} }
private PackedBytes buf; private PackedBytes buf;
private ArrayList<LabelRef> labelref = null; private ArrayList<LabelRef> labelref = null;
/** /**
* Pcode emitter constructor for producing a packed binary representation * Pcode emitter constructor for producing a packed binary representation
* for unimplemented or empty responses. * for unimplemented or empty responses.
@ -60,7 +56,7 @@ public class PcodeEmitPacked extends PcodeEmit {
super(); super();
buf = new PackedBytes(64); buf = new PackedBytes(64);
} }
/** /**
* Pcode emitter constructor for producing a packed binary representation. * Pcode emitter constructor for producing a packed binary representation.
* @param delayContexts delay slotted instruction contexts * @param delayContexts delay slotted instruction contexts
@ -68,76 +64,86 @@ public class PcodeEmitPacked extends PcodeEmit {
* @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 * @param uniqueFactory required when override specified or if overlay normalization is required
*/ */
public PcodeEmitPacked(ParserWalker walk,InstructionContext ictx, int fallOffset, PcodeOverride override, UniqueAddressFactory uniqueFactory) { public PcodeEmitPacked(ParserWalker walk, InstructionContext ictx, int fallOffset,
super(walk,ictx,fallOffset,override,uniqueFactory); PcodeOverride override, UniqueAddressFactory uniqueFactory) {
super(walk, ictx, fallOffset, override, uniqueFactory);
buf = new PackedBytes(512); buf = new PackedBytes(512);
} }
public PackedBytes getPackedBytes() { public PackedBytes getPackedBytes() {
return buf; return buf;
} }
@Override @Override
public void resolveRelatives() { public void resolveRelatives() {
if (labelref==null) return; if (labelref == null) {
for(int i=0;i<labelref.size();++i) { return;
}
for (int i = 0; i < labelref.size(); ++i) {
LabelRef ref = labelref.get(i); 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");
long res = (long)labeldef.get(ref.labelIndex) - (long)ref.opIndex; }
long res = (long) labeldef.get(ref.labelIndex) - (long) ref.opIndex;
if (ref.labelSize < 8) { if (ref.labelSize < 8) {
long mask = -1; long mask = -1;
mask >>>= (8-ref.labelSize)*8; mask >>>= (8 - ref.labelSize) * 8;
res &= mask; res &= mask;
} }
// We need to skip over op_tag, op_code, void_tag, addrsz_tag, and spc bytes // We need to skip over op_tag, op_code, void_tag, addrsz_tag, and spc bytes
insertOffset(ref.streampos+5,res); // Insert the final offset into the stream insertOffset(ref.streampos + 5, res); // Insert the final offset into the stream
} }
} }
/* (non-Javadoc) /* (non-Javadoc)
* @see ghidra.app.plugin.processors.sleigh.PcodeEmit#addLabelRef() * @see ghidra.app.plugin.processors.sleigh.PcodeEmit#addLabelRef()
*/ */
@Override
void addLabelRef() { void addLabelRef() {
if (labelref == null) if (labelref == null) {
labelref = new ArrayList<LabelRef>(); labelref = new ArrayList<LabelRef>();
int labelIndex = (int)incache[0].offset; }
int labelIndex = (int) incache[0].offset;
int labelSize = incache[0].size; int labelSize = incache[0].size;
// Force the emitter to write out a maximum length encoding (12 bytes) of a long // Force the emitter to write out a maximum length encoding (12 bytes) of a long
// so that we have space to insert whatever value we need to when this relative is resolved // so that we have space to insert whatever value we need to when this relative is resolved
incache[0].offset = -1; incache[0].offset = -1;
labelref.add(new LabelRef(numOps,labelIndex,labelSize,buf.size())); labelref.add(new LabelRef(numOps, labelIndex, labelSize, buf.size()));
} }
/* (non-Javadoc) /* (non-Javadoc)
* @see ghidra.app.plugin.processors.sleigh.PcodeEmit#dump(ghidra.program.model.address.Address, int, ghidra.app.plugin.processors.sleigh.VarnodeData[], int, ghidra.app.plugin.processors.sleigh.VarnodeData) * @see ghidra.app.plugin.processors.sleigh.PcodeEmit#dump(ghidra.program.model.address.Address, int, ghidra.app.plugin.processors.sleigh.VarnodeData[], int, ghidra.app.plugin.processors.sleigh.VarnodeData)
*/ */
void dump(Address instrAddr, int opcode,VarnodeData[] in,int isize,VarnodeData out) { @Override
checkOverrides(opcode,in); void dump(Address instrAddr, int opcode, VarnodeData[] in, int isize, VarnodeData out) {
checkOverlays(opcode,in,isize,out); opcode = checkOverrides(opcode, in);
checkOverlays(opcode, in, isize, out);
buf.write(op_tag); buf.write(op_tag);
buf.write(opcode + 0x20); buf.write(opcode + 0x20);
if (out==null) if (out == null) {
buf.write(void_tag); buf.write(void_tag);
else }
else {
dumpVarnodeData(out); dumpVarnodeData(out);
int i=0; }
if ((opcode==PcodeOp.LOAD)||(opcode==PcodeOp.STORE)) { int i = 0;
if ((opcode == PcodeOp.LOAD) || (opcode == PcodeOp.STORE)) {
dumpSpaceId(in[0]); dumpSpaceId(in[0]);
i = 1; i = 1;
} }
for(;i<isize;++i) for (; i < isize; ++i) {
dumpVarnodeData(in[i]); dumpVarnodeData(in[i]);
}
buf.write(end_tag); buf.write(end_tag);
} }
private void dumpSpaceId(VarnodeData v) { private void dumpSpaceId(VarnodeData v) {
buf.write(spaceid_tag); buf.write(spaceid_tag);
int spcindex = ((int)v.offset >> AddressSpace.ID_UNIQUE_SHIFT); int spcindex = ((int) v.offset >> AddressSpace.ID_UNIQUE_SHIFT);
buf.write(spcindex + 0x20); buf.write(spcindex + 0x20);
} }
private void dumpVarnodeData(VarnodeData v) { private void dumpVarnodeData(VarnodeData v) {
buf.write(addrsz_tag); buf.write(addrsz_tag);
int spcindex = v.space.getUnique(); int spcindex = v.space.getUnique();
@ -145,37 +151,40 @@ public class PcodeEmitPacked extends PcodeEmit {
dumpOffset(v.offset); dumpOffset(v.offset);
buf.write(v.size + 0x20); buf.write(v.size + 0x20);
} }
public void write(int val) { public void write(int val) {
buf.write(val); buf.write(val);
} }
/** /**
* Encode and dump an integer value to the packed byte stream * Encode and dump an integer value to the packed byte stream
* @param val is the integer to write * @param val is the integer to write
*/ */
public void dumpOffset(long val) { public void dumpOffset(long val) {
while (val!=0) { while (val != 0) {
int chunk = (int)(val & 0x3f); int chunk = (int) (val & 0x3f);
val >>>= 6; val >>>= 6;
buf.write(chunk + 0x20); buf.write(chunk + 0x20);
} }
buf.write(end_tag); buf.write(end_tag);
} }
private void insertOffset(int streampos,long val) { private void insertOffset(int streampos, long val) {
while(val!=0) { while (val != 0) {
if (buf.getByte(streampos)==end_tag) if (buf.getByte(streampos) == end_tag) {
throw new SleighException("Could not properly insert relative jump offset"); throw new SleighException("Could not properly insert relative jump offset");
int chunk = (int)(val & 0x3f); }
int chunk = (int) (val & 0x3f);
val >>>= 6; val >>>= 6;
buf.insertByte(streampos,chunk + 0x20); buf.insertByte(streampos, chunk + 0x20);
streampos += 1; streampos += 1;
} }
for(int i=0;i<11;++i) { for (int i = 0; i < 11; ++i) {
if (buf.getByte(streampos)==end_tag) return; if (buf.getByte(streampos) == end_tag) {
buf.insertByte(streampos,0x20); // Zero fill return;
streampos += 1; }
buf.insertByte(streampos, 0x20); // Zero fill
streampos += 1;
} }
throw new SleighException("Could not find terminator while inserting relative jump offset"); throw new SleighException("Could not find terminator while inserting relative jump offset");
} }

View File

@ -19,6 +19,7 @@ import ghidra.program.model.address.Address;
import ghidra.program.model.lang.InjectPayload; import ghidra.program.model.lang.InjectPayload;
import ghidra.program.model.pcode.PcodeOverride; import ghidra.program.model.pcode.PcodeOverride;
import ghidra.program.model.symbol.Reference; import ghidra.program.model.symbol.Reference;
import ghidra.program.model.symbol.SourceType;
import ghidra.util.Msg; import ghidra.util.Msg;
public class InstructionPcodeOverride implements PcodeOverride { public class InstructionPcodeOverride implements PcodeOverride {
@ -50,9 +51,10 @@ public class InstructionPcodeOverride implements PcodeOverride {
} }
@Override @Override
public Address getPrimaryCallReference() { public Address getOverridingCallReference() {
for (Reference ref : instr.getReferencesFrom()) { for (Reference ref : instr.getReferencesFrom()) {
if (ref.isPrimary() && ref.getReferenceType().isCall()) { if (ref.getSource().equals(SourceType.USER_DEFINED) && ref.isPrimary() &&
ref.getReferenceType().isCall()) {
return ref.getToAddress(); return ref.getToAddress();
} }
} }

View File

@ -18,9 +18,10 @@ package ghidra.program.model.pcode;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.lang.InjectPayload; import ghidra.program.model.lang.InjectPayload;
import ghidra.program.model.listing.FlowOverride; import ghidra.program.model.listing.FlowOverride;
import ghidra.program.model.symbol.SourceType;
public interface PcodeOverride { public interface PcodeOverride {
/** /**
* @return current instruction address * @return current instruction address
*/ */
@ -34,10 +35,11 @@ public interface PcodeOverride {
FlowOverride getFlowOverride(); FlowOverride getFlowOverride();
/** /**
* Get the primary call reference address from the current instruction * Get the primary call reference address (whose {@link SourceType} must be {@link SourceType#USER_DEFINED})
* from the current instruction
* @return call reference address or null * @return call reference address or null
*/ */
Address getPrimaryCallReference(); Address getOverridingCallReference();
/** /**
* Get the fall-through override address which may have been * Get the fall-through override address which may have been
@ -45,23 +47,23 @@ public interface PcodeOverride {
* @return fall-through override address or null * @return fall-through override address or null
*/ */
Address getFallThroughOverride(); Address getFallThroughOverride();
/** /**
* Returns the call-fixup for a specified call destination. * Returns the call-fixup for a specified call destination.
* @param callDestAddr call destination address. This address is used to * @param callDestAddr call destination address. This address is used to
* identify a function which may have been tagged with a CallFixup. * identify a function which may have been tagged with a CallFixup.
* @return true if call destination function has been tagged with a call-fixup * @return true if call destination function has been tagged with a call-fixup
*/ */
boolean hasCallFixup(Address callDestAddr); boolean hasCallFixup(Address callDestAddr);
/** /**
* Returns the call-fixup for a specified call destination. * Returns the call-fixup for a specified call destination.
* If the destination function has not be tagged or was tagged * If the destination function has not be tagged or was tagged
* with an unknown CallFixup name this method will return null. * with an unknown CallFixup name this method will return null.
* @param callDestAddr call destination address. This address is used to * @param callDestAddr call destination address. This address is used to
* identify a function which may have been tagged with a CallFixup. * identify a function which may have been tagged with a CallFixup.
* @return call fixup object or null * @return call fixup object or null
*/ */
InjectPayload getCallFixup(Address callDestAddr); InjectPayload getCallFixup(Address callDestAddr);
} }