mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-11-24 21:21:56 +00:00
GT-2816 added ability to override indirect call destinations
This commit is contained in:
parent
4ce178c419
commit
fa14932797
@ -149,7 +149,7 @@ public abstract class PcodeEmit {
|
||||
public ParserWalker getWalker() {
|
||||
return walker;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Make a note of the current op index, and associate
|
||||
* it with the label index from the label template,
|
||||
@ -158,11 +158,13 @@ public abstract class PcodeEmit {
|
||||
* @param op = the label template op
|
||||
*/
|
||||
private void setLabel(OpTpl op) {
|
||||
if (labeldef == null)
|
||||
if (labeldef == null) {
|
||||
labeldef = new ArrayList<Integer>();
|
||||
}
|
||||
int labelindex = (int) op.getInput()[0].getOffset().getReal() + labelbase;
|
||||
while (labeldef.size() <= labelindex)
|
||||
while (labeldef.size() <= labelindex) {
|
||||
labeldef.add(null);
|
||||
}
|
||||
labeldef.set(labelindex, numOps);
|
||||
}
|
||||
|
||||
@ -205,8 +207,8 @@ public abstract class PcodeEmit {
|
||||
private void dumpNullReturn() {
|
||||
|
||||
VarnodeTpl nullAddr =
|
||||
new VarnodeTpl(new ConstTpl(const_space), new ConstTpl(ConstTpl.REAL, 0), new ConstTpl(
|
||||
ConstTpl.REAL, const_space.getPointerSize()));
|
||||
new VarnodeTpl(new ConstTpl(const_space), new ConstTpl(ConstTpl.REAL, 0),
|
||||
new ConstTpl(ConstTpl.REAL, const_space.getPointerSize()));
|
||||
|
||||
OpTpl retOpt = new OpTpl(PcodeOp.RETURN, null, new VarnodeTpl[] { nullAddr });
|
||||
dump(retOpt);
|
||||
@ -253,13 +255,11 @@ public abstract class PcodeEmit {
|
||||
// <label>
|
||||
|
||||
Address tmpAddr = uniqueFactory.getNextUniqueAddress();
|
||||
VarnodeTpl tmp =
|
||||
new VarnodeTpl(new ConstTpl(tmpAddr.getAddressSpace()), new ConstTpl(ConstTpl.REAL,
|
||||
tmpAddr.getOffset()), inputs[1].getSize());
|
||||
VarnodeTpl tmp = new VarnodeTpl(new ConstTpl(tmpAddr.getAddressSpace()),
|
||||
new ConstTpl(ConstTpl.REAL, tmpAddr.getOffset()), inputs[1].getSize());
|
||||
int labelIndex = labelcount++;
|
||||
VarnodeTpl label =
|
||||
new VarnodeTpl(new ConstTpl(const_space), new ConstTpl(ConstTpl.J_RELATIVE,
|
||||
labelIndex), new ConstTpl(ConstTpl.REAL, 8));
|
||||
VarnodeTpl label = new VarnodeTpl(new ConstTpl(const_space),
|
||||
new ConstTpl(ConstTpl.J_RELATIVE, labelIndex), new ConstTpl(ConstTpl.REAL, 8));
|
||||
VarnodeTpl dest = inputs[0];
|
||||
VarnodeTpl cond = inputs[1];
|
||||
|
||||
@ -311,13 +311,12 @@ public abstract class PcodeEmit {
|
||||
// RETURN tmp
|
||||
|
||||
Address tmpAddr = uniqueFactory.getNextUniqueAddress();
|
||||
VarnodeTpl tmp =
|
||||
new VarnodeTpl(new ConstTpl(tmpAddr.getAddressSpace()), new ConstTpl(ConstTpl.REAL,
|
||||
tmpAddr.getOffset()), new ConstTpl(ConstTpl.REAL, ptrSize));
|
||||
VarnodeTpl tmp = new VarnodeTpl(new ConstTpl(tmpAddr.getAddressSpace()),
|
||||
new ConstTpl(ConstTpl.REAL, tmpAddr.getOffset()),
|
||||
new ConstTpl(ConstTpl.REAL, ptrSize));
|
||||
|
||||
VarnodeTpl destAddr =
|
||||
new VarnodeTpl(new ConstTpl(const_space), inputs[0].getOffset(), new ConstTpl(
|
||||
ConstTpl.REAL, ptrSize));
|
||||
VarnodeTpl destAddr = new VarnodeTpl(new ConstTpl(const_space), inputs[0].getOffset(),
|
||||
new ConstTpl(ConstTpl.REAL, ptrSize));
|
||||
|
||||
OpTpl copyOpt = new OpTpl(PcodeOp.COPY, tmp, new VarnodeTpl[] { destAddr });
|
||||
dump(copyOpt);
|
||||
@ -353,23 +352,20 @@ public abstract class PcodeEmit {
|
||||
// <label>
|
||||
|
||||
Address tmpAddr = uniqueFactory.getNextUniqueAddress();
|
||||
VarnodeTpl tmp =
|
||||
new VarnodeTpl(new ConstTpl(tmpAddr.getAddressSpace()), new ConstTpl(ConstTpl.REAL,
|
||||
tmpAddr.getOffset()), inputs[1].getSize());
|
||||
VarnodeTpl tmp = new VarnodeTpl(new ConstTpl(tmpAddr.getAddressSpace()),
|
||||
new ConstTpl(ConstTpl.REAL, tmpAddr.getOffset()), inputs[1].getSize());
|
||||
|
||||
tmpAddr = uniqueFactory.getNextUniqueAddress();
|
||||
VarnodeTpl tmp2 =
|
||||
new VarnodeTpl(new ConstTpl(tmpAddr.getAddressSpace()), new ConstTpl(ConstTpl.REAL,
|
||||
tmpAddr.getOffset()), new ConstTpl(ConstTpl.REAL, ptrSize));
|
||||
VarnodeTpl tmp2 = new VarnodeTpl(new ConstTpl(tmpAddr.getAddressSpace()),
|
||||
new ConstTpl(ConstTpl.REAL, tmpAddr.getOffset()),
|
||||
new ConstTpl(ConstTpl.REAL, ptrSize));
|
||||
|
||||
VarnodeTpl destAddr =
|
||||
new VarnodeTpl(new ConstTpl(const_space), inputs[0].getOffset(), new ConstTpl(
|
||||
ConstTpl.REAL, ptrSize));
|
||||
VarnodeTpl destAddr = new VarnodeTpl(new ConstTpl(const_space), inputs[0].getOffset(),
|
||||
new ConstTpl(ConstTpl.REAL, ptrSize));
|
||||
|
||||
int labelIndex = labelcount++;
|
||||
VarnodeTpl label =
|
||||
new VarnodeTpl(new ConstTpl(const_space), new ConstTpl(ConstTpl.J_RELATIVE,
|
||||
labelIndex), new ConstTpl(ConstTpl.REAL, 8));
|
||||
VarnodeTpl label = new VarnodeTpl(new ConstTpl(const_space),
|
||||
new ConstTpl(ConstTpl.J_RELATIVE, labelIndex), new ConstTpl(ConstTpl.REAL, 8));
|
||||
VarnodeTpl cond = inputs[1];
|
||||
|
||||
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) {
|
||||
vn.space = vntpl.getSpace().fixSpace(walker);
|
||||
vn.size = (int) vntpl.getSize().fix(walker);
|
||||
if (vn.space == const_space)
|
||||
if (vn.space == const_space) {
|
||||
vn.offset =
|
||||
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;
|
||||
else
|
||||
}
|
||||
else {
|
||||
vn.offset = vn.space.truncateOffset(vntpl.getOffset().fix(walker));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -439,12 +438,15 @@ public abstract class PcodeEmit {
|
||||
FixedHandle hand = walker.getFixedHandle(vntpl.getOffset().getHandleIndex());
|
||||
vn.space = hand.offset_space;
|
||||
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];
|
||||
else if (vn.space == uniq_space)
|
||||
}
|
||||
else if (vn.space == uniq_space) {
|
||||
vn.offset = hand.offset_offset | uniqueoffset;
|
||||
else
|
||||
}
|
||||
else {
|
||||
vn.offset = vn.space.truncateOffset(hand.offset_offset);
|
||||
}
|
||||
return hand.space;
|
||||
}
|
||||
|
||||
@ -473,8 +475,9 @@ public abstract class PcodeEmit {
|
||||
dump(startAddress, PcodeOp.LOAD, dyncache, 2, dyncache[2]);
|
||||
numOps += 1;
|
||||
}
|
||||
else
|
||||
else {
|
||||
generateLocation(vn, incache[i]);
|
||||
}
|
||||
}
|
||||
if ((isize > 0) && (opt.getInput()[0].isRelative())) {
|
||||
incache[0].offset += labelbase;
|
||||
@ -515,22 +518,25 @@ public abstract class PcodeEmit {
|
||||
}
|
||||
}
|
||||
|
||||
private void appendBuild(OpTpl bld, int secnum) throws UnknownInstructionException,
|
||||
MemoryAccessException {
|
||||
private void appendBuild(OpTpl bld, int secnum)
|
||||
throws UnknownInstructionException, MemoryAccessException {
|
||||
// Recover operand index from build statement
|
||||
int index = (int) bld.getInput()[0].getOffset().getReal();
|
||||
Symbol sym = walker.getConstructor().getOperand(index).getDefiningSymbol();
|
||||
if ((sym == null) || (!(sym instanceof SubtableSymbol)))
|
||||
if ((sym == null) || (!(sym instanceof SubtableSymbol))) {
|
||||
return;
|
||||
}
|
||||
|
||||
walker.pushOperand(index);
|
||||
Constructor ct = walker.getConstructor();
|
||||
if (secnum >= 0) {
|
||||
ConstructTpl construct = ct.getNamedTempl(secnum);
|
||||
if (construct == null)
|
||||
if (construct == null) {
|
||||
buildEmpty(ct, secnum);
|
||||
else
|
||||
}
|
||||
else {
|
||||
build(construct, secnum);
|
||||
}
|
||||
}
|
||||
else {
|
||||
ConstructTpl construct = ct.getTempl();
|
||||
@ -548,8 +554,8 @@ public abstract class PcodeEmit {
|
||||
private void delaySlot(OpTpl op) throws UnknownInstructionException, MemoryAccessException {
|
||||
|
||||
if (inDelaySlot) {
|
||||
throw new SleighException("Delay Slot recursion problem for Instruction at " +
|
||||
walker.getAddr());
|
||||
throw new SleighException(
|
||||
"Delay Slot recursion problem for Instruction at " + walker.getAddr());
|
||||
}
|
||||
inDelaySlot = true;
|
||||
Address baseaddr = parsercontext.getAddr();
|
||||
@ -589,11 +595,12 @@ public abstract class PcodeEmit {
|
||||
* @throws UnknownInstructionException
|
||||
* @throws MemoryAccessException
|
||||
*/
|
||||
private void appendCrossBuild(OpTpl bld, int secnum) throws UnknownInstructionException,
|
||||
MemoryAccessException {
|
||||
if (secnum >= 0)
|
||||
throw new SleighException("CROSSBUILD recursion problem for instruction at " +
|
||||
walker.getAddr());
|
||||
private void appendCrossBuild(OpTpl bld, int secnum)
|
||||
throws UnknownInstructionException, MemoryAccessException {
|
||||
if (secnum >= 0) {
|
||||
throw new SleighException(
|
||||
"CROSSBUILD recursion problem for instruction at " + walker.getAddr());
|
||||
}
|
||||
secnum = (int) bld.getInput()[1].getOffset().getReal();
|
||||
VarnodeTpl vn = bld.getInput()[0];
|
||||
AddressSpace spc = vn.getSpace().fixSpace(walker);
|
||||
@ -609,35 +616,38 @@ public abstract class PcodeEmit {
|
||||
parsercontext = (SleighParserContext) instcontext.getParserContext(addr);
|
||||
}
|
||||
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.baseState();
|
||||
Constructor ct = walker.getConstructor();
|
||||
ConstructTpl construct = ct.getNamedTempl(secnum);
|
||||
if (construct == null)
|
||||
if (construct == null) {
|
||||
buildEmpty(ct, secnum);
|
||||
else
|
||||
}
|
||||
else {
|
||||
build(construct, secnum);
|
||||
}
|
||||
walker = oldwalker;
|
||||
parsercontext = walker.getParserContext();
|
||||
uniqueoffset = olduniqueoffset;
|
||||
}
|
||||
|
||||
public void build(ConstructTpl construct, int secnum) throws UnknownInstructionException,
|
||||
MemoryAccessException {
|
||||
if (construct == null)
|
||||
public void build(ConstructTpl construct, int secnum)
|
||||
throws UnknownInstructionException, MemoryAccessException {
|
||||
if (construct == null) {
|
||||
throw new NotYetImplementedException(
|
||||
"Semantics for this instruction are not implemented");
|
||||
}
|
||||
|
||||
int oldbase = labelbase; // Recursively save old labelbase
|
||||
labelbase = labelcount;
|
||||
labelcount += construct.getNumLabels();
|
||||
|
||||
OpTpl[] optpllist = construct.getOpVec();
|
||||
for (int i = 0; i < optpllist.length; ++i) {
|
||||
OpTpl op = optpllist[i];
|
||||
for (OpTpl op : optpllist) {
|
||||
switch (op.getOpcode()) {
|
||||
case PcodeOp.MULTIEQUAL: // Build placeholder
|
||||
appendBuild(op, secnum);
|
||||
@ -668,28 +678,32 @@ public abstract class PcodeEmit {
|
||||
* @throws MemoryAccessException
|
||||
* @throws UnknownInstructionException
|
||||
*/
|
||||
private void buildEmpty(Constructor ct, int secnum) throws UnknownInstructionException,
|
||||
MemoryAccessException {
|
||||
private void buildEmpty(Constructor ct, int secnum)
|
||||
throws UnknownInstructionException, MemoryAccessException {
|
||||
int numops = ct.getNumOperands();
|
||||
|
||||
for (int i = 0; i < numops; ++i) {
|
||||
TripleSymbol sym = ct.getOperand(i).getDefiningSymbol();
|
||||
if ((sym == null) || (!(sym instanceof SubtableSymbol)))
|
||||
if ((sym == null) || (!(sym instanceof SubtableSymbol))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
walker.pushOperand(i);
|
||||
ConstructTpl construct = walker.getConstructor().getNamedTempl(secnum);
|
||||
if (construct == null)
|
||||
if (construct == null) {
|
||||
buildEmpty(walker.getConstructor(), secnum);
|
||||
else
|
||||
}
|
||||
else {
|
||||
build(construct, secnum);
|
||||
}
|
||||
walker.popOperand();
|
||||
}
|
||||
}
|
||||
|
||||
void checkOverlays(int opcode, VarnodeData[] in, int isize, VarnodeData out) {
|
||||
if (uniqueFactory == null)
|
||||
if (uniqueFactory == null) {
|
||||
return;
|
||||
}
|
||||
if ((opcode == PcodeOp.LOAD) || (opcode == PcodeOp.STORE)) {
|
||||
int spaceId = (int) in[0].offset;
|
||||
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) {
|
||||
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
|
||||
// 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))) {
|
||||
// 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))) {
|
||||
// Check for call reference (not supported if call-fixup exists for the instruction)
|
||||
Address callRef = override.getPrimaryCallReference();
|
||||
Address callRef = override.getOverridingCallReference();
|
||||
if (callRef != null) {
|
||||
VarnodeData dest = in[0];
|
||||
dest.space = callRef.getAddressSpace();
|
||||
@ -740,6 +774,6 @@ public abstract class PcodeEmit {
|
||||
dest.size = dest.space.getPointerSize();
|
||||
}
|
||||
}
|
||||
|
||||
return opcode;
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -16,40 +15,36 @@
|
||||
*/
|
||||
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 ghidra.program.model.address.*;
|
||||
import ghidra.program.model.lang.InstructionContext;
|
||||
import ghidra.program.model.pcode.*;
|
||||
|
||||
public class PcodeEmitObjects extends PcodeEmit {
|
||||
|
||||
|
||||
private ArrayList<PcodeOp> oplist;
|
||||
private ArrayList<Integer> labelref = null;
|
||||
|
||||
|
||||
/**
|
||||
* Pcode emitter constructor for producing PcodeOp objects for unimplemented, snippets or empty responses
|
||||
* when {@link #getFallOffset()} will not be used.
|
||||
* @param walk state of the ParserContext from which to generate p-code
|
||||
*/
|
||||
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.
|
||||
* @param walk state of the ParserContext from which to generate p-code
|
||||
* @param fallOffset default fall-through offset (i.e., the full length
|
||||
* of instruction including delay-sloted instructions)
|
||||
*/
|
||||
public PcodeEmitObjects(ParserWalker walk,int fallOffset) { // For use with emitting precompiled p-code templates
|
||||
this(walk,null,fallOffset,null,null);
|
||||
public PcodeEmitObjects(ParserWalker walk, int fallOffset) { // For use with emitting precompiled p-code templates
|
||||
this(walk, null, fallOffset, null, null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param walk state of the ParserContext from which to generate p-code
|
||||
* @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 uniqueFactory required when override specified or if overlay normalization is required
|
||||
*/
|
||||
public PcodeEmitObjects(ParserWalker walk,InstructionContext ictx, int fallOffset, PcodeOverride override, UniqueAddressFactory uniqueFactory) {
|
||||
super(walk,ictx,fallOffset,override,uniqueFactory);
|
||||
public PcodeEmitObjects(ParserWalker walk, InstructionContext ictx, int fallOffset,
|
||||
PcodeOverride override, UniqueAddressFactory uniqueFactory) {
|
||||
super(walk, ictx, fallOffset, override, uniqueFactory);
|
||||
oplist = new ArrayList<PcodeOp>();
|
||||
}
|
||||
|
||||
|
||||
public PcodeOp[] getPcodeOp() {
|
||||
PcodeOp[] retop = new PcodeOp[oplist.size()];
|
||||
oplist.toArray(retop);
|
||||
return retop;
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.app.plugin.processors.sleigh.PcodeEmit#resolveRelatives()
|
||||
*/
|
||||
@Override
|
||||
public void resolveRelatives() {
|
||||
if (labelref==null) return;
|
||||
for(int i=0;i<labelref.size();++i) {
|
||||
if (labelref == null) {
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < labelref.size(); ++i) {
|
||||
int opindex = labelref.get(i);
|
||||
PcodeOp op = oplist.get(opindex);
|
||||
Varnode vn = op.getInput(0);
|
||||
int labelid = (int)vn.getOffset();
|
||||
if ((labelid>=labeldef.size())||(labeldef.get(labelid)==null))
|
||||
int labelid = (int) vn.getOffset();
|
||||
if ((labelid >= labeldef.size()) || (labeldef.get(labelid) == null)) {
|
||||
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) {
|
||||
long mask = -1;
|
||||
mask >>>= (8-vn.getSize())*8;
|
||||
mask >>>= (8 - vn.getSize()) * 8;
|
||||
res &= mask;
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.app.plugin.processors.sleigh.PcodeEmit#addLabelRef()
|
||||
*/
|
||||
@Override
|
||||
void addLabelRef() {
|
||||
if (labelref == null)
|
||||
if (labelref == null) {
|
||||
labelref = new ArrayList<Integer>();
|
||||
}
|
||||
labelref.add(numOps);
|
||||
}
|
||||
|
||||
|
||||
/* (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)
|
||||
*/
|
||||
void dump(Address instrAddr, int opcode,VarnodeData[] in,int isize,VarnodeData out) {
|
||||
checkOverrides(opcode,in);
|
||||
@Override
|
||||
void dump(Address instrAddr, int opcode, VarnodeData[] in, int isize, VarnodeData out) {
|
||||
opcode = checkOverrides(opcode, in);
|
||||
Varnode outvn;
|
||||
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;
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -28,30 +28,26 @@ import ghidra.program.model.pcode.PcodeOverride;
|
||||
*
|
||||
*/
|
||||
public class PcodeEmitPacked extends PcodeEmit {
|
||||
public final static int unimpl_tag = 0x20,
|
||||
inst_tag = 0x21,
|
||||
op_tag = 0x22,
|
||||
void_tag = 0x23,
|
||||
spaceid_tag = 0x24,
|
||||
addrsz_tag = 0x25,
|
||||
end_tag = 0x60; // End of a number
|
||||
|
||||
public final static int unimpl_tag = 0x20, inst_tag = 0x21, op_tag = 0x22, void_tag = 0x23,
|
||||
spaceid_tag = 0x24, addrsz_tag = 0x25, end_tag = 0x60; // End of a number
|
||||
|
||||
public class LabelRef {
|
||||
public int opIndex; // Index of operation referencing the label
|
||||
public int labelIndex; // Index of label being referenced
|
||||
public int labelSize; // Number of bytes in the label
|
||||
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;
|
||||
labelIndex = lab;
|
||||
labelSize = size;
|
||||
streampos = stream;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private PackedBytes buf;
|
||||
private ArrayList<LabelRef> labelref = null;
|
||||
|
||||
|
||||
/**
|
||||
* Pcode emitter constructor for producing a packed binary representation
|
||||
* for unimplemented or empty responses.
|
||||
@ -60,7 +56,7 @@ public class PcodeEmitPacked extends PcodeEmit {
|
||||
super();
|
||||
buf = new PackedBytes(64);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Pcode emitter constructor for producing a packed binary representation.
|
||||
* @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 uniqueFactory required when override specified or if overlay normalization is required
|
||||
*/
|
||||
public PcodeEmitPacked(ParserWalker walk,InstructionContext ictx, int fallOffset, PcodeOverride override, UniqueAddressFactory uniqueFactory) {
|
||||
super(walk,ictx,fallOffset,override,uniqueFactory);
|
||||
public PcodeEmitPacked(ParserWalker walk, InstructionContext ictx, int fallOffset,
|
||||
PcodeOverride override, UniqueAddressFactory uniqueFactory) {
|
||||
super(walk, ictx, fallOffset, override, uniqueFactory);
|
||||
buf = new PackedBytes(512);
|
||||
}
|
||||
|
||||
|
||||
public PackedBytes getPackedBytes() {
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void resolveRelatives() {
|
||||
if (labelref==null) return;
|
||||
for(int i=0;i<labelref.size();++i) {
|
||||
if (labelref == null) {
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < labelref.size(); ++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");
|
||||
long res = (long)labeldef.get(ref.labelIndex) - (long)ref.opIndex;
|
||||
}
|
||||
long res = (long) labeldef.get(ref.labelIndex) - (long) ref.opIndex;
|
||||
if (ref.labelSize < 8) {
|
||||
long mask = -1;
|
||||
mask >>>= (8-ref.labelSize)*8;
|
||||
mask >>>= (8 - ref.labelSize) * 8;
|
||||
res &= mask;
|
||||
}
|
||||
// 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)
|
||||
* @see ghidra.app.plugin.processors.sleigh.PcodeEmit#addLabelRef()
|
||||
*/
|
||||
@Override
|
||||
void addLabelRef() {
|
||||
if (labelref == null)
|
||||
if (labelref == null) {
|
||||
labelref = new ArrayList<LabelRef>();
|
||||
int labelIndex = (int)incache[0].offset;
|
||||
}
|
||||
int labelIndex = (int) incache[0].offset;
|
||||
int labelSize = incache[0].size;
|
||||
// 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
|
||||
incache[0].offset = -1;
|
||||
|
||||
labelref.add(new LabelRef(numOps,labelIndex,labelSize,buf.size()));
|
||||
|
||||
labelref.add(new LabelRef(numOps, labelIndex, labelSize, buf.size()));
|
||||
}
|
||||
|
||||
|
||||
/* (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)
|
||||
*/
|
||||
void dump(Address instrAddr, int opcode,VarnodeData[] in,int isize,VarnodeData out) {
|
||||
checkOverrides(opcode,in);
|
||||
checkOverlays(opcode,in,isize,out);
|
||||
@Override
|
||||
void dump(Address instrAddr, int opcode, VarnodeData[] in, int isize, VarnodeData out) {
|
||||
opcode = checkOverrides(opcode, in);
|
||||
checkOverlays(opcode, in, isize, out);
|
||||
buf.write(op_tag);
|
||||
buf.write(opcode + 0x20);
|
||||
if (out==null)
|
||||
if (out == null) {
|
||||
buf.write(void_tag);
|
||||
else
|
||||
}
|
||||
else {
|
||||
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]);
|
||||
i = 1;
|
||||
}
|
||||
for(;i<isize;++i)
|
||||
for (; i < isize; ++i) {
|
||||
dumpVarnodeData(in[i]);
|
||||
}
|
||||
buf.write(end_tag);
|
||||
}
|
||||
|
||||
private void dumpSpaceId(VarnodeData v) {
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
private void dumpVarnodeData(VarnodeData v) {
|
||||
buf.write(addrsz_tag);
|
||||
int spcindex = v.space.getUnique();
|
||||
@ -145,37 +151,40 @@ public class PcodeEmitPacked extends PcodeEmit {
|
||||
dumpOffset(v.offset);
|
||||
buf.write(v.size + 0x20);
|
||||
}
|
||||
|
||||
|
||||
public void write(int val) {
|
||||
buf.write(val);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Encode and dump an integer value to the packed byte stream
|
||||
* @param val is the integer to write
|
||||
*/
|
||||
public void dumpOffset(long val) {
|
||||
while (val!=0) {
|
||||
int chunk = (int)(val & 0x3f);
|
||||
while (val != 0) {
|
||||
int chunk = (int) (val & 0x3f);
|
||||
val >>>= 6;
|
||||
buf.write(chunk + 0x20);
|
||||
}
|
||||
buf.write(end_tag);
|
||||
}
|
||||
|
||||
private void insertOffset(int streampos,long val) {
|
||||
while(val!=0) {
|
||||
if (buf.getByte(streampos)==end_tag)
|
||||
|
||||
private void insertOffset(int streampos, long val) {
|
||||
while (val != 0) {
|
||||
if (buf.getByte(streampos) == end_tag) {
|
||||
throw new SleighException("Could not properly insert relative jump offset");
|
||||
int chunk = (int)(val & 0x3f);
|
||||
}
|
||||
int chunk = (int) (val & 0x3f);
|
||||
val >>>= 6;
|
||||
buf.insertByte(streampos,chunk + 0x20);
|
||||
buf.insertByte(streampos, chunk + 0x20);
|
||||
streampos += 1;
|
||||
}
|
||||
for(int i=0;i<11;++i) {
|
||||
if (buf.getByte(streampos)==end_tag) return;
|
||||
buf.insertByte(streampos,0x20); // Zero fill
|
||||
streampos += 1;
|
||||
for (int i = 0; i < 11; ++i) {
|
||||
if (buf.getByte(streampos) == end_tag) {
|
||||
return;
|
||||
}
|
||||
buf.insertByte(streampos, 0x20); // Zero fill
|
||||
streampos += 1;
|
||||
}
|
||||
throw new SleighException("Could not find terminator while inserting relative jump offset");
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.lang.InjectPayload;
|
||||
import ghidra.program.model.pcode.PcodeOverride;
|
||||
import ghidra.program.model.symbol.Reference;
|
||||
import ghidra.program.model.symbol.SourceType;
|
||||
import ghidra.util.Msg;
|
||||
|
||||
public class InstructionPcodeOverride implements PcodeOverride {
|
||||
@ -50,9 +51,10 @@ public class InstructionPcodeOverride implements PcodeOverride {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Address getPrimaryCallReference() {
|
||||
public Address getOverridingCallReference() {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
@ -18,9 +18,10 @@ package ghidra.program.model.pcode;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.lang.InjectPayload;
|
||||
import ghidra.program.model.listing.FlowOverride;
|
||||
import ghidra.program.model.symbol.SourceType;
|
||||
|
||||
public interface PcodeOverride {
|
||||
|
||||
|
||||
/**
|
||||
* @return current instruction address
|
||||
*/
|
||||
@ -34,10 +35,11 @@ public interface PcodeOverride {
|
||||
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
|
||||
*/
|
||||
Address getPrimaryCallReference();
|
||||
Address getOverridingCallReference();
|
||||
|
||||
/**
|
||||
* Get the fall-through override address which may have been
|
||||
@ -45,23 +47,23 @@ public interface PcodeOverride {
|
||||
* @return fall-through override address or null
|
||||
*/
|
||||
Address getFallThroughOverride();
|
||||
|
||||
|
||||
/**
|
||||
* Returns the call-fixup for a specified call destination.
|
||||
* @param callDestAddr call destination address. This address is used to
|
||||
* identify a function which may have been tagged with a CallFixup.
|
||||
* @return true if call destination function has been tagged with a call-fixup
|
||||
*/
|
||||
* Returns the call-fixup for a specified call destination.
|
||||
* @param callDestAddr call destination address. This address is used to
|
||||
* identify a function which may have been tagged with a CallFixup.
|
||||
* @return true if call destination function has been tagged with a call-fixup
|
||||
*/
|
||||
boolean hasCallFixup(Address callDestAddr);
|
||||
|
||||
|
||||
/**
|
||||
* Returns the call-fixup for a specified call destination.
|
||||
* If the destination function has not be tagged or was tagged
|
||||
* with an unknown CallFixup name this method will return null.
|
||||
* @param callDestAddr call destination address. This address is used to
|
||||
* identify a function which may have been tagged with a CallFixup.
|
||||
* @return call fixup object or null
|
||||
*/
|
||||
* Returns the call-fixup for a specified call destination.
|
||||
* If the destination function has not be tagged or was tagged
|
||||
* with an unknown CallFixup name this method will return null.
|
||||
* @param callDestAddr call destination address. This address is used to
|
||||
* identify a function which may have been tagged with a CallFixup.
|
||||
* @return call fixup object or null
|
||||
*/
|
||||
InjectPayload getCallFixup(Address callDestAddr);
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user