mirror of
https://github.com/NationalSecurityAgency/ghidra
synced 2024-09-18 01:31:53 +00:00
GP-2480 Add sleigh compiler support for inst_next2
This commit is contained in:
parent
39baf3a691
commit
8d4a6c213e
|
@ -105,14 +105,14 @@ public class DebuggerStateEditingPluginIntegrationTest extends AbstractGhidraHea
|
||||||
assertTrue(
|
assertTrue(
|
||||||
helper.patchInstructionAction.isAddToPopup(listingProvider.getActionContext(null)));
|
helper.patchInstructionAction.isAddToPopup(listingProvider.getActionContext(null)));
|
||||||
Instruction ins =
|
Instruction ins =
|
||||||
helper.patchInstructionAt(tb.addr(0x00400123), "imm r0,#0x0", "imm r0,#1234");
|
helper.patchInstructionAt(tb.addr(0x00400123), "imm r0,#0x0", "imm r0,#0x3d2");
|
||||||
assertEquals(2, ins.getLength());
|
assertEquals(2, ins.getLength());
|
||||||
|
|
||||||
long snap = traceManager.getCurrent().getViewSnap();
|
long snap = traceManager.getCurrent().getViewSnap();
|
||||||
assertTrue(DBTraceUtils.isScratch(snap));
|
assertTrue(DBTraceUtils.isScratch(snap));
|
||||||
byte[] bytes = new byte[2];
|
byte[] bytes = new byte[2];
|
||||||
view.getMemory().getBytes(tb.addr(0x00400123), bytes);
|
view.getMemory().getBytes(tb.addr(0x00400123), bytes);
|
||||||
assertArrayEquals(tb.arr(0x40, 1234), bytes);
|
assertArrayEquals(tb.arr(0x30, 0xd2), bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -86,8 +86,8 @@ public class DebuggerPcodeStepperProviderTest extends AbstractGhidraHeadedDebugg
|
||||||
|
|
||||||
Assembler asm = Assemblers.getAssembler(tb.trace.getFixedProgramView(0));
|
Assembler asm = Assemblers.getAssembler(tb.trace.getFixedProgramView(0));
|
||||||
iit = asm.assemble(start,
|
iit = asm.assemble(start,
|
||||||
"imm r0, #1234",
|
"imm r0, #0x3d2",
|
||||||
"imm r1, #2045"); // 11 bits unsigned
|
"imm r1, #911"); // 10 bits unsigned
|
||||||
|
|
||||||
}
|
}
|
||||||
imm1234 = iit.next();
|
imm1234 = iit.next();
|
||||||
|
|
|
@ -309,7 +309,7 @@ public class TracePcodeEmulatorTest extends AbstractGhidraHeadlessIntegrationTes
|
||||||
"pc = 0x00400000;",
|
"pc = 0x00400000;",
|
||||||
"sp = 0x00110000;"),
|
"sp = 0x00110000;"),
|
||||||
List.of(
|
List.of(
|
||||||
"imm r0, #1234")); // decimal
|
"imm r0, #911")); // decimal
|
||||||
|
|
||||||
TracePcodeEmulator emu = new TracePcodeEmulator(tb.trace, 0);
|
TracePcodeEmulator emu = new TracePcodeEmulator(tb.trace, 0);
|
||||||
PcodeThread<byte[]> emuThread = emu.newThread(thread.getPath());
|
PcodeThread<byte[]> emuThread = emu.newThread(thread.getPath());
|
||||||
|
@ -324,7 +324,7 @@ public class TracePcodeEmulatorTest extends AbstractGhidraHeadlessIntegrationTes
|
||||||
TraceSleighUtils.evaluate("sp", tb.trace, 1, thread, 0));
|
TraceSleighUtils.evaluate("sp", tb.trace, 1, thread, 0));
|
||||||
assertEquals(BigInteger.valueOf(0x00400002),
|
assertEquals(BigInteger.valueOf(0x00400002),
|
||||||
TraceSleighUtils.evaluate("pc", tb.trace, 1, thread, 0));
|
TraceSleighUtils.evaluate("pc", tb.trace, 1, thread, 0));
|
||||||
assertEquals(BigInteger.valueOf(1234),
|
assertEquals(BigInteger.valueOf(911),
|
||||||
TraceSleighUtils.evaluate("r0", tb.trace, 1, thread, 0));
|
TraceSleighUtils.evaluate("r0", tb.trace, 1, thread, 0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -341,9 +341,9 @@ public class TracePcodeEmulatorTest extends AbstractGhidraHeadlessIntegrationTes
|
||||||
"sp = 0x00110000;"),
|
"sp = 0x00110000;"),
|
||||||
List.of(
|
List.of(
|
||||||
"brds 0x00400006",
|
"brds 0x00400006",
|
||||||
"imm r0, #1234", // decimal
|
"imm r0, #911", // decimal
|
||||||
"imm r0, #2020",
|
"imm r0, #860",
|
||||||
"imm r1, #2021"));
|
"imm r1, #861"));
|
||||||
|
|
||||||
TracePcodeEmulator emu = new TracePcodeEmulator(tb.trace, 0);
|
TracePcodeEmulator emu = new TracePcodeEmulator(tb.trace, 0);
|
||||||
PcodeThread<byte[]> emuThread = emu.newThread(thread.getPath());
|
PcodeThread<byte[]> emuThread = emu.newThread(thread.getPath());
|
||||||
|
@ -357,9 +357,9 @@ public class TracePcodeEmulatorTest extends AbstractGhidraHeadlessIntegrationTes
|
||||||
|
|
||||||
assertEquals(BigInteger.valueOf(0x00400008),
|
assertEquals(BigInteger.valueOf(0x00400008),
|
||||||
TraceSleighUtils.evaluate("pc", tb.trace, 1, thread, 0));
|
TraceSleighUtils.evaluate("pc", tb.trace, 1, thread, 0));
|
||||||
assertEquals(BigInteger.valueOf(1234),
|
assertEquals(BigInteger.valueOf(911),
|
||||||
TraceSleighUtils.evaluate("r0", tb.trace, 1, thread, 0));
|
TraceSleighUtils.evaluate("r0", tb.trace, 1, thread, 0));
|
||||||
assertEquals(BigInteger.valueOf(2021),
|
assertEquals(BigInteger.valueOf(861),
|
||||||
TraceSleighUtils.evaluate("r1", tb.trace, 1, thread, 0));
|
TraceSleighUtils.evaluate("r1", tb.trace, 1, thread, 0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -176,6 +176,9 @@ public abstract class AbstractPcodeFormatter<T, A extends Appender<T>>
|
||||||
else if (offset.getType() == ConstTpl.J_NEXT) {
|
else if (offset.getType() == ConstTpl.J_NEXT) {
|
||||||
appender.appendLabel("inst_next");
|
appender.appendLabel("inst_next");
|
||||||
}
|
}
|
||||||
|
else if (offset.getType() == ConstTpl.J_NEXT2) {
|
||||||
|
appender.appendLabel("inst_next2");
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
formatAddress(appender, null, offset, size);
|
formatAddress(appender, null, offset, size);
|
||||||
}
|
}
|
||||||
|
|
|
@ -494,6 +494,27 @@ public class ToyProgramBuilder extends ProgramBuilder {
|
||||||
addInstructionWords(address, (short) (0xe000 | (relDest << 4))); // breq rel
|
addInstructionWords(address, (short) (0xe000 | (relDest << 4))); // breq rel
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add conditional skip (consumes 2-bytes)
|
||||||
|
* @param offset instruction address offset
|
||||||
|
* @throws MemoryAccessException
|
||||||
|
*/
|
||||||
|
public void addBytesSkipConditional(long offset)
|
||||||
|
throws MemoryAccessException {
|
||||||
|
addBytesSkipConditional(toHex(offset));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add conditional skip (consumes 2-bytes)
|
||||||
|
* @param addr instruction address
|
||||||
|
* @throws MemoryAccessException
|
||||||
|
*/
|
||||||
|
public void addBytesSkipConditional(String addr)
|
||||||
|
throws MemoryAccessException {
|
||||||
|
Address address = addr(addr);
|
||||||
|
addInstructionWords(address, (short) (0x8000)); // skeq
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add branch w/ delay slot (consumes 4-bytes)
|
* Add branch w/ delay slot (consumes 4-bytes)
|
||||||
* @param offset instruction address offset
|
* @param offset instruction address offset
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.plugin.core.assembler;
|
package ghidra.app.plugin.core.assembler;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
import org.junit.*;
|
import org.junit.*;
|
||||||
|
|
||||||
|
@ -90,8 +90,8 @@ public class AssemblerPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
@Test
|
@Test
|
||||||
public void testActionPatchInstructionNoExisting() throws Exception {
|
public void testActionPatchInstructionNoExisting() throws Exception {
|
||||||
Address address = space.getAddress(0x00400000);
|
Address address = space.getAddress(0x00400000);
|
||||||
Instruction ins = helper.patchInstructionAt(address, "", "imm r0, #1234");
|
Instruction ins = helper.patchInstructionAt(address, "", "imm r0, #911");
|
||||||
assertEquals("imm r0,#0x4d2", ins.toString());
|
assertEquals("imm r0,#0x38f", ins.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -99,11 +99,11 @@ public class AssemblerPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
Address address = space.getAddress(0x00400000);
|
Address address = space.getAddress(0x00400000);
|
||||||
Assembler asm = Assemblers.getAssembler(program);
|
Assembler asm = Assemblers.getAssembler(program);
|
||||||
try (ProgramTransaction trans = ProgramTransaction.open(program, "Assemble pre-existing")) {
|
try (ProgramTransaction trans = ProgramTransaction.open(program, "Assemble pre-existing")) {
|
||||||
asm.assemble(address, "imm r0,#0x4d2");
|
asm.assemble(address, "imm r0,#0x3d2");
|
||||||
trans.commit();
|
trans.commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
Instruction ins = helper.patchInstructionAt(address, "imm r0,#0x4d2", "imm r0, #123");
|
Instruction ins = helper.patchInstructionAt(address, "imm r0,#0x3d2", "imm r0, #123");
|
||||||
assertEquals("imm r0,#0x7b", ins.toString());
|
assertEquals("imm r0,#0x7b", ins.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -106,6 +106,7 @@ public:
|
||||||
void applyCommits(void);
|
void applyCommits(void);
|
||||||
const Address &getAddr(void) const { return addr; }
|
const Address &getAddr(void) const { return addr; }
|
||||||
const Address &getNaddr(void) const { return naddr; }
|
const Address &getNaddr(void) const { return naddr; }
|
||||||
|
const Address &getN2addr(void) const { return naddr; /* inst_next2 not supported */ }
|
||||||
const Address &getDestAddr(void) const { return calladdr; }
|
const Address &getDestAddr(void) const { return calladdr; }
|
||||||
const Address &getRefAddr(void) const { return calladdr; }
|
const Address &getRefAddr(void) const { return calladdr; }
|
||||||
AddrSpace *getCurSpace(void) const { return addr.getSpace(); }
|
AddrSpace *getCurSpace(void) const { return addr.getSpace(); }
|
||||||
|
@ -147,6 +148,7 @@ public:
|
||||||
AddrSpace *getConstSpace(void) const { return const_context->getConstSpace(); }
|
AddrSpace *getConstSpace(void) const { return const_context->getConstSpace(); }
|
||||||
const Address &getAddr(void) const { if (cross_context != (const ParserContext *)0) { return cross_context->getAddr(); } return const_context->getAddr(); }
|
const Address &getAddr(void) const { if (cross_context != (const ParserContext *)0) { return cross_context->getAddr(); } return const_context->getAddr(); }
|
||||||
const Address &getNaddr(void) const { if (cross_context != (const ParserContext *)0) { return cross_context->getNaddr();} return const_context->getNaddr(); }
|
const Address &getNaddr(void) const { if (cross_context != (const ParserContext *)0) { return cross_context->getNaddr();} return const_context->getNaddr(); }
|
||||||
|
const Address &getN2addr(void) const { if (cross_context != (const ParserContext *)0) { return cross_context->getN2addr();} return const_context->getN2addr(); }
|
||||||
const Address &getRefAddr(void) const { if (cross_context != (const ParserContext *)0) { return cross_context->getRefAddr();} return const_context->getRefAddr(); }
|
const Address &getRefAddr(void) const { if (cross_context != (const ParserContext *)0) { return cross_context->getRefAddr();} return const_context->getRefAddr(); }
|
||||||
const Address &getDestAddr(void) const { if (cross_context != (const ParserContext *)0) { return cross_context->getDestAddr();} return const_context->getDestAddr(); }
|
const Address &getDestAddr(void) const { if (cross_context != (const ParserContext *)0) { return cross_context->getDestAddr();} return const_context->getDestAddr(); }
|
||||||
int4 getLength(void) const { return const_context->getLength(); }
|
int4 getLength(void) const { return const_context->getLength(); }
|
||||||
|
|
|
@ -791,7 +791,7 @@ void Funcdata::doLiveInject(InjectPayload *payload,const Address &addr,BlockBasi
|
||||||
|
|
||||||
emitter.setFuncdata(this);
|
emitter.setFuncdata(this);
|
||||||
context.clear();
|
context.clear();
|
||||||
context.baseaddr = addr; // Shouldn't be using inst_next and inst_start here
|
context.baseaddr = addr; // Shouldn't be using inst_next, inst_next2 or inst_start here
|
||||||
context.nextaddr = addr;
|
context.nextaddr = addr;
|
||||||
|
|
||||||
list<PcodeOp *>::const_iterator deaditer = obank.endDead();
|
list<PcodeOp *>::const_iterator deaditer = obank.endDead();
|
||||||
|
|
|
@ -69,6 +69,7 @@ public:
|
||||||
/// concrete Varnodes. This class contains the context dependent data to resolve:
|
/// concrete Varnodes. This class contains the context dependent data to resolve:
|
||||||
/// - inst_start -- the address where the injection occurs
|
/// - inst_start -- the address where the injection occurs
|
||||||
/// - inst_next -- the address of the instruction following (the instruction being injected)
|
/// - inst_next -- the address of the instruction following (the instruction being injected)
|
||||||
|
/// - inst_next2 -- the address of the instruction after the next instruction (Not Supported)
|
||||||
/// - inst_dest -- Original destination of CALL being injected
|
/// - inst_dest -- Original destination of CALL being injected
|
||||||
/// - inst_ref -- Target of reference on injected instruction
|
/// - inst_ref -- Target of reference on injected instruction
|
||||||
/// - \<input> -- Input Varnode of the injection referenced by name
|
/// - \<input> -- Input Varnode of the injection referenced by name
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -38,6 +38,7 @@
|
||||||
LabelSymbol *labelsym;
|
LabelSymbol *labelsym;
|
||||||
StartSymbol *startsym;
|
StartSymbol *startsym;
|
||||||
EndSymbol *endsym;
|
EndSymbol *endsym;
|
||||||
|
Next2Symbol *next2sym;
|
||||||
OperandSymbol *operandsym;
|
OperandSymbol *operandsym;
|
||||||
VarnodeSymbol *varsym;
|
VarnodeSymbol *varsym;
|
||||||
SpecificSymbol *specsym;
|
SpecificSymbol *specsym;
|
||||||
|
@ -76,6 +77,7 @@
|
||||||
%token <operandsym> OPERANDSYM
|
%token <operandsym> OPERANDSYM
|
||||||
%token <startsym> STARTSYM
|
%token <startsym> STARTSYM
|
||||||
%token <endsym> ENDSYM
|
%token <endsym> ENDSYM
|
||||||
|
%token <next2sym> NEXT2SYM
|
||||||
%token <labelsym> LABELSYM
|
%token <labelsym> LABELSYM
|
||||||
|
|
||||||
%type <param> paramlist
|
%type <param> paramlist
|
||||||
|
@ -195,6 +197,7 @@ sizedstar: '*' '[' SPACESYM ']' ':' INTEGER { $$ = new StarQuality; $$->size = *
|
||||||
;
|
;
|
||||||
jumpdest: STARTSYM { VarnodeTpl *sym = $1->getVarnode(); $$ = new VarnodeTpl(ConstTpl(ConstTpl::j_curspace),sym->getOffset(),ConstTpl(ConstTpl::j_curspace_size)); delete sym; }
|
jumpdest: STARTSYM { VarnodeTpl *sym = $1->getVarnode(); $$ = new VarnodeTpl(ConstTpl(ConstTpl::j_curspace),sym->getOffset(),ConstTpl(ConstTpl::j_curspace_size)); delete sym; }
|
||||||
| ENDSYM { VarnodeTpl *sym = $1->getVarnode(); $$ = new VarnodeTpl(ConstTpl(ConstTpl::j_curspace),sym->getOffset(),ConstTpl(ConstTpl::j_curspace_size)); delete sym; }
|
| ENDSYM { VarnodeTpl *sym = $1->getVarnode(); $$ = new VarnodeTpl(ConstTpl(ConstTpl::j_curspace),sym->getOffset(),ConstTpl(ConstTpl::j_curspace_size)); delete sym; }
|
||||||
|
| NEXT2SYM { VarnodeTpl *sym = $1->getVarnode(); $$ = new VarnodeTpl(ConstTpl(ConstTpl::j_curspace),sym->getOffset(),ConstTpl(ConstTpl::j_curspace_size)); delete sym; }
|
||||||
| INTEGER { $$ = new VarnodeTpl(ConstTpl(ConstTpl::j_curspace),ConstTpl(ConstTpl::real,*$1),ConstTpl(ConstTpl::j_curspace_size)); delete $1; }
|
| INTEGER { $$ = new VarnodeTpl(ConstTpl(ConstTpl::j_curspace),ConstTpl(ConstTpl::real,*$1),ConstTpl(ConstTpl::j_curspace_size)); delete $1; }
|
||||||
| BADINTEGER { $$ = new VarnodeTpl(ConstTpl(ConstTpl::j_curspace),ConstTpl(ConstTpl::real,0),ConstTpl(ConstTpl::j_curspace_size)); yyerror("Parsed integer is too big (overflow)"); }
|
| BADINTEGER { $$ = new VarnodeTpl(ConstTpl(ConstTpl::j_curspace),ConstTpl(ConstTpl::real,0),ConstTpl(ConstTpl::j_curspace_size)); yyerror("Parsed integer is too big (overflow)"); }
|
||||||
| INTEGER '[' SPACESYM ']' { AddrSpace *spc = $3->getSpace(); $$ = new VarnodeTpl(ConstTpl(spc),ConstTpl(ConstTpl::real,*$1),ConstTpl(ConstTpl::real,spc->getAddrSize())); delete $1; }
|
| INTEGER '[' SPACESYM ']' { AddrSpace *spc = $3->getSpace(); $$ = new VarnodeTpl(ConstTpl(spc),ConstTpl(ConstTpl::real,*$1),ConstTpl(ConstTpl::real,spc->getAddrSize())); delete $1; }
|
||||||
|
@ -221,6 +224,7 @@ specificsymbol: VARSYM { $$ = $1; }
|
||||||
| OPERANDSYM { $$ = $1; }
|
| OPERANDSYM { $$ = $1; }
|
||||||
| STARTSYM { $$ = $1; }
|
| STARTSYM { $$ = $1; }
|
||||||
| ENDSYM { $$ = $1; }
|
| ENDSYM { $$ = $1; }
|
||||||
|
| NEXT2SYM { $$ = $1; }
|
||||||
;
|
;
|
||||||
paramlist: /* EMPTY */ { $$ = new vector<ExprTree *>; }
|
paramlist: /* EMPTY */ { $$ = new vector<ExprTree *>; }
|
||||||
| expr { $$ = new vector<ExprTree *>; $$->push_back($1); }
|
| expr { $$ = new vector<ExprTree *>; $$->push_back($1); }
|
||||||
|
@ -749,6 +753,9 @@ int4 PcodeSnippet::lex(void)
|
||||||
case SleighSymbol::end_symbol:
|
case SleighSymbol::end_symbol:
|
||||||
yylval.endsym = (EndSymbol *)sym;
|
yylval.endsym = (EndSymbol *)sym;
|
||||||
return ENDSYM;
|
return ENDSYM;
|
||||||
|
case SleighSymbol::next2_symbol:
|
||||||
|
yylval.next2sym = (Next2Symbol *)sym;
|
||||||
|
return NEXT2SYM;
|
||||||
case SleighSymbol::label_symbol:
|
case SleighSymbol::label_symbol:
|
||||||
yylval.labelsym = (LabelSymbol *)sym;
|
yylval.labelsym = (LabelSymbol *)sym;
|
||||||
return LABELSYM;
|
return LABELSYM;
|
||||||
|
|
|
@ -121,6 +121,8 @@ uintb ConstTpl::fix(const ParserWalker &walker) const
|
||||||
return walker.getAddr().getOffset(); // Fill in starting address placeholder with real address
|
return walker.getAddr().getOffset(); // Fill in starting address placeholder with real address
|
||||||
case j_next:
|
case j_next:
|
||||||
return walker.getNaddr().getOffset(); // Fill in next address placeholder with real address
|
return walker.getNaddr().getOffset(); // Fill in next address placeholder with real address
|
||||||
|
case j_next2:
|
||||||
|
return walker.getN2addr().getOffset(); // Fill in next2 address placeholder with real address
|
||||||
case j_flowref:
|
case j_flowref:
|
||||||
return walker.getRefAddr().getOffset();
|
return walker.getRefAddr().getOffset();
|
||||||
case j_flowref_size:
|
case j_flowref_size:
|
||||||
|
@ -349,6 +351,9 @@ void ConstTpl::saveXml(ostream &s) const
|
||||||
case j_next:
|
case j_next:
|
||||||
s << "next\"/>";
|
s << "next\"/>";
|
||||||
break;
|
break;
|
||||||
|
case j_next2:
|
||||||
|
s << "next2\"/>";
|
||||||
|
break;
|
||||||
case j_curspace:
|
case j_curspace:
|
||||||
s << "curspace\"/>";
|
s << "curspace\"/>";
|
||||||
break;
|
break;
|
||||||
|
@ -404,6 +409,9 @@ void ConstTpl::restoreXml(const Element *el,const AddrSpaceManager *manage)
|
||||||
else if (typestring=="next") {
|
else if (typestring=="next") {
|
||||||
type = j_next;
|
type = j_next;
|
||||||
}
|
}
|
||||||
|
else if (typestring=="next2") {
|
||||||
|
type = j_next2;
|
||||||
|
}
|
||||||
else if (typestring=="curspace") {
|
else if (typestring=="curspace") {
|
||||||
type = j_curspace;
|
type = j_curspace;
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,9 +30,9 @@ class Translate; // Forward declaration
|
||||||
class HandleTpl; // Forward declaration
|
class HandleTpl; // Forward declaration
|
||||||
class ConstTpl {
|
class ConstTpl {
|
||||||
public:
|
public:
|
||||||
enum const_type { real=0, handle=1, j_start=2, j_next=3, j_curspace=4,
|
enum const_type { real=0, handle=1, j_start=2, j_next=3, j_next2=4, j_curspace=5,
|
||||||
j_curspace_size=5, spaceid=6, j_relative=7,
|
j_curspace_size=6, spaceid=7, j_relative=8,
|
||||||
j_flowref=8, j_flowref_size=9, j_flowdest=10, j_flowdest_size=11 };
|
j_flowref=9, j_flowref_size=10, j_flowdest=11, j_flowdest_size=12 };
|
||||||
enum v_field { v_space=0, v_offset=1, v_size=2, v_offset_plus=3 };
|
enum v_field { v_space=0, v_offset=1, v_size=2, v_offset_plus=3 };
|
||||||
private:
|
private:
|
||||||
const_type type;
|
const_type type;
|
||||||
|
|
|
@ -1789,7 +1789,7 @@ SleighCompile::SleighCompile(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create the address spaces: \b const, \b unique, and \b other.
|
/// Create the address spaces: \b const, \b unique, and \b other.
|
||||||
/// Define the special symbols: \b inst_start, \b inst_next, \b epsilon.
|
/// Define the special symbols: \b inst_start, \b inst_next, \b inst_next2, \b epsilon.
|
||||||
/// Define the root subtable symbol: \b instruction
|
/// Define the root subtable symbol: \b instruction
|
||||||
void SleighCompile::predefinedSymbols(void)
|
void SleighCompile::predefinedSymbols(void)
|
||||||
|
|
||||||
|
@ -1813,6 +1813,8 @@ void SleighCompile::predefinedSymbols(void)
|
||||||
symtab.addSymbol(startsym);
|
symtab.addSymbol(startsym);
|
||||||
EndSymbol *endsym = new EndSymbol("inst_next",getConstantSpace());
|
EndSymbol *endsym = new EndSymbol("inst_next",getConstantSpace());
|
||||||
symtab.addSymbol(endsym);
|
symtab.addSymbol(endsym);
|
||||||
|
Next2Symbol *next2sym = new Next2Symbol("inst_next2",getConstantSpace());
|
||||||
|
symtab.addSymbol(next2sym);
|
||||||
EpsilonSymbol *epsilon = new EpsilonSymbol("epsilon",getConstantSpace());
|
EpsilonSymbol *epsilon = new EpsilonSymbol("epsilon",getConstantSpace());
|
||||||
symtab.addSymbol(epsilon);
|
symtab.addSymbol(epsilon);
|
||||||
pcode.setConstantSpace(getConstantSpace());
|
pcode.setConstantSpace(getConstantSpace());
|
||||||
|
@ -2907,20 +2909,23 @@ ConstructTpl *SleighCompile::setResultStarVarnode(ConstructTpl *ct,StarQuality *
|
||||||
/// The new change operation is added to the current list.
|
/// The new change operation is added to the current list.
|
||||||
/// When executed, the change operation will assign a new value to the given context variable
|
/// When executed, the change operation will assign a new value to the given context variable
|
||||||
/// using the specified expression. The change only applies within the parsing of a single instruction.
|
/// using the specified expression. The change only applies within the parsing of a single instruction.
|
||||||
/// Because we are in the middle of parsing, the \b inst_next value has not been computed yet
|
/// Because we are in the middle of parsing, the \b inst_next and \b inst_next2 values have not
|
||||||
/// So we check to make sure the value expression doesn't use this symbol.
|
/// been computed yet. So we check to make sure the value expression doesn't use this symbol.
|
||||||
/// \param vec is the current list of change operations
|
/// \param vec is the current list of change operations
|
||||||
/// \param sym is the given context variable affected by the operation
|
/// \param sym is the given context variable affected by the operation
|
||||||
/// \param pe is the specified expression
|
/// \param pe is the specified expression
|
||||||
/// \return \b true if the expression does not use the \b inst_next symbol
|
/// \return \b true if the expression does not use the \b inst_next or \b inst_next2 symbol
|
||||||
bool SleighCompile::contextMod(vector<ContextChange *> *vec,ContextSymbol *sym,PatternExpression *pe)
|
bool SleighCompile::contextMod(vector<ContextChange *> *vec,ContextSymbol *sym,PatternExpression *pe)
|
||||||
|
|
||||||
{
|
{
|
||||||
vector<const PatternValue *> vallist;
|
vector<const PatternValue *> vallist;
|
||||||
pe->listValues(vallist);
|
pe->listValues(vallist);
|
||||||
for(uint4 i=0;i<vallist.size();++i)
|
for(uint4 i=0;i<vallist.size();++i) {
|
||||||
if (dynamic_cast<const EndInstructionValue *>(vallist[i]) != (const EndInstructionValue *)0)
|
if (dynamic_cast<const EndInstructionValue *>(vallist[i]) != (const EndInstructionValue *)0)
|
||||||
return false;
|
return false;
|
||||||
|
if (dynamic_cast<const Next2InstructionValue *>(vallist[i]) != (const Next2InstructionValue *)0)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
// Otherwise we generate a "temporary" change to context instruction (ContextOp)
|
// Otherwise we generate a "temporary" change to context instruction (ContextOp)
|
||||||
ContextField *field = (ContextField *)sym->getPatternValue();
|
ContextField *field = (ContextField *)sym->getPatternValue();
|
||||||
ContextOp *op = new ContextOp(field->getStartBit(),field->getEndBit(),pe);
|
ContextOp *op = new ContextOp(field->getStartBit(),field->getEndBit(),pe);
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -45,8 +45,8 @@
|
||||||
This special exception was added by the Free Software Foundation in
|
This special exception was added by the Free Software Foundation in
|
||||||
version 2.2 of Bison. */
|
version 2.2 of Bison. */
|
||||||
|
|
||||||
#ifndef YY_YY_SRC_DECOMPILE_CPP_SLGHPARSE_HH_INCLUDED
|
#ifndef YY_YY_SLGHPARSE_HH_INCLUDED
|
||||||
# define YY_YY_SRC_DECOMPILE_CPP_SLGHPARSE_HH_INCLUDED
|
# define YY_YY_SLGHPARSE_HH_INCLUDED
|
||||||
/* Debug traces. */
|
/* Debug traces. */
|
||||||
#ifndef YYDEBUG
|
#ifndef YYDEBUG
|
||||||
# define YYDEBUG 0
|
# define YYDEBUG 0
|
||||||
|
@ -168,9 +168,10 @@ extern int yydebug;
|
||||||
OPERANDSYM = 363,
|
OPERANDSYM = 363,
|
||||||
STARTSYM = 364,
|
STARTSYM = 364,
|
||||||
ENDSYM = 365,
|
ENDSYM = 365,
|
||||||
MACROSYM = 366,
|
NEXT2SYM = 366,
|
||||||
LABELSYM = 367,
|
MACROSYM = 367,
|
||||||
SUBTABLESYM = 368
|
LABELSYM = 368,
|
||||||
|
SUBTABLESYM = 369
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -179,7 +180,7 @@ extern int yydebug;
|
||||||
|
|
||||||
union YYSTYPE
|
union YYSTYPE
|
||||||
{
|
{
|
||||||
#line 29 "src/decompile/cpp/slghparse.y" /* yacc.c:1909 */
|
#line 29 "slghparse.y" /* yacc.c:1909 */
|
||||||
|
|
||||||
char ch;
|
char ch;
|
||||||
uintb *i;
|
uintb *i;
|
||||||
|
@ -212,6 +213,7 @@ union YYSTYPE
|
||||||
SubtableSymbol *subtablesym;
|
SubtableSymbol *subtablesym;
|
||||||
StartSymbol *startsym;
|
StartSymbol *startsym;
|
||||||
EndSymbol *endsym;
|
EndSymbol *endsym;
|
||||||
|
Next2Symbol *next2sym;
|
||||||
OperandSymbol *operandsym;
|
OperandSymbol *operandsym;
|
||||||
VarnodeListSymbol *varlistsym;
|
VarnodeListSymbol *varlistsym;
|
||||||
VarnodeSymbol *varsym;
|
VarnodeSymbol *varsym;
|
||||||
|
@ -223,7 +225,7 @@ union YYSTYPE
|
||||||
FamilySymbol *famsym;
|
FamilySymbol *famsym;
|
||||||
SpecificSymbol *specsym;
|
SpecificSymbol *specsym;
|
||||||
|
|
||||||
#line 212 "src/decompile/cpp/slghparse.hh" /* yacc.c:1909 */
|
#line 214 "slghparse.hh" /* yacc.c:1909 */
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef union YYSTYPE YYSTYPE;
|
typedef union YYSTYPE YYSTYPE;
|
||||||
|
@ -236,4 +238,4 @@ extern YYSTYPE yylval;
|
||||||
|
|
||||||
int yyparse (void);
|
int yyparse (void);
|
||||||
|
|
||||||
#endif /* !YY_YY_SRC_DECOMPILE_CPP_SLGHPARSE_HH_INCLUDED */
|
#endif /* !YY_YY_SLGHPARSE_HH_INCLUDED */
|
||||||
|
|
|
@ -58,6 +58,7 @@
|
||||||
SubtableSymbol *subtablesym;
|
SubtableSymbol *subtablesym;
|
||||||
StartSymbol *startsym;
|
StartSymbol *startsym;
|
||||||
EndSymbol *endsym;
|
EndSymbol *endsym;
|
||||||
|
Next2Symbol *next2sym;
|
||||||
OperandSymbol *operandsym;
|
OperandSymbol *operandsym;
|
||||||
VarnodeListSymbol *varlistsym;
|
VarnodeListSymbol *varlistsym;
|
||||||
VarnodeSymbol *varsym;
|
VarnodeSymbol *varsym;
|
||||||
|
@ -121,6 +122,7 @@
|
||||||
%token <operandsym> OPERANDSYM
|
%token <operandsym> OPERANDSYM
|
||||||
%token <startsym> STARTSYM
|
%token <startsym> STARTSYM
|
||||||
%token <endsym> ENDSYM
|
%token <endsym> ENDSYM
|
||||||
|
%token <next2sym> NEXT2SYM
|
||||||
%token <macrosym> MACROSYM
|
%token <macrosym> MACROSYM
|
||||||
%token <labelsym> LABELSYM
|
%token <labelsym> LABELSYM
|
||||||
%token <subtablesym> SUBTABLESYM
|
%token <subtablesym> SUBTABLESYM
|
||||||
|
@ -331,7 +333,7 @@ contextblock: { $$ = (vector<ContextChange *> *)0; }
|
||||||
| '[' contextlist ']' { $$ = $2; }
|
| '[' contextlist ']' { $$ = $2; }
|
||||||
;
|
;
|
||||||
contextlist: { $$ = new vector<ContextChange *>; }
|
contextlist: { $$ = new vector<ContextChange *>; }
|
||||||
| contextlist CONTEXTSYM '=' pexpression ';' { $$ = $1; if (!slgh->contextMod($1,$2,$4)) { string errmsg="Cannot use 'inst_next' to set context variable: "+$2->getName(); yyerror(errmsg.c_str()); YYERROR; } }
|
| contextlist CONTEXTSYM '=' pexpression ';' { $$ = $1; if (!slgh->contextMod($1,$2,$4)) { string errmsg="Cannot use 'inst_next' or 'inst_next2' to set context variable: "+$2->getName(); yyerror(errmsg.c_str()); YYERROR; } }
|
||||||
| contextlist GLOBALSET_KEY '(' familysymbol ',' CONTEXTSYM ')' ';' { $$ = $1; slgh->contextSet($1,$4,$6); }
|
| contextlist GLOBALSET_KEY '(' familysymbol ',' CONTEXTSYM ')' ';' { $$ = $1; slgh->contextSet($1,$4,$6); }
|
||||||
| contextlist GLOBALSET_KEY '(' specificsymbol ',' CONTEXTSYM ')' ';' { $$ = $1; slgh->contextSet($1,$4,$6); }
|
| contextlist GLOBALSET_KEY '(' specificsymbol ',' CONTEXTSYM ')' ';' { $$ = $1; slgh->contextSet($1,$4,$6); }
|
||||||
| contextlist OPERANDSYM '=' pexpression ';' { $$ = $1; slgh->defineOperand($2,$4); }
|
| contextlist OPERANDSYM '=' pexpression ';' { $$ = $1; slgh->defineOperand($2,$4); }
|
||||||
|
@ -456,6 +458,7 @@ sizedstar: '*' '[' SPACESYM ']' ':' INTEGER { $$ = new StarQuality; $$->size = *
|
||||||
;
|
;
|
||||||
jumpdest: STARTSYM { VarnodeTpl *sym = $1->getVarnode(); $$ = new VarnodeTpl(ConstTpl(ConstTpl::j_curspace),sym->getOffset(),ConstTpl(ConstTpl::j_curspace_size)); delete sym; }
|
jumpdest: STARTSYM { VarnodeTpl *sym = $1->getVarnode(); $$ = new VarnodeTpl(ConstTpl(ConstTpl::j_curspace),sym->getOffset(),ConstTpl(ConstTpl::j_curspace_size)); delete sym; }
|
||||||
| ENDSYM { VarnodeTpl *sym = $1->getVarnode(); $$ = new VarnodeTpl(ConstTpl(ConstTpl::j_curspace),sym->getOffset(),ConstTpl(ConstTpl::j_curspace_size)); delete sym; }
|
| ENDSYM { VarnodeTpl *sym = $1->getVarnode(); $$ = new VarnodeTpl(ConstTpl(ConstTpl::j_curspace),sym->getOffset(),ConstTpl(ConstTpl::j_curspace_size)); delete sym; }
|
||||||
|
| NEXT2SYM { VarnodeTpl *sym = $1->getVarnode(); $$ = new VarnodeTpl(ConstTpl(ConstTpl::j_curspace),sym->getOffset(),ConstTpl(ConstTpl::j_curspace_size)); delete sym; }
|
||||||
| INTEGER { $$ = new VarnodeTpl(ConstTpl(ConstTpl::j_curspace),ConstTpl(ConstTpl::real,*$1),ConstTpl(ConstTpl::j_curspace_size)); delete $1; }
|
| INTEGER { $$ = new VarnodeTpl(ConstTpl(ConstTpl::j_curspace),ConstTpl(ConstTpl::real,*$1),ConstTpl(ConstTpl::j_curspace_size)); delete $1; }
|
||||||
| BADINTEGER { $$ = new VarnodeTpl(ConstTpl(ConstTpl::j_curspace),ConstTpl(ConstTpl::real,0),ConstTpl(ConstTpl::j_curspace_size)); yyerror("Parsed integer is too big (overflow)"); }
|
| BADINTEGER { $$ = new VarnodeTpl(ConstTpl(ConstTpl::j_curspace),ConstTpl(ConstTpl::real,0),ConstTpl(ConstTpl::j_curspace_size)); yyerror("Parsed integer is too big (overflow)"); }
|
||||||
| OPERANDSYM { $$ = $1->getVarnode(); $1->setCodeAddress(); }
|
| OPERANDSYM { $$ = $1->getVarnode(); $1->setCodeAddress(); }
|
||||||
|
@ -499,6 +502,7 @@ specificsymbol: VARSYM { $$ = $1; }
|
||||||
| OPERANDSYM { $$ = $1; }
|
| OPERANDSYM { $$ = $1; }
|
||||||
| STARTSYM { $$ = $1; }
|
| STARTSYM { $$ = $1; }
|
||||||
| ENDSYM { $$ = $1; }
|
| ENDSYM { $$ = $1; }
|
||||||
|
| NEXT2SYM { $$ = $1; }
|
||||||
;
|
;
|
||||||
charstring: CHAR { $$ = new string; (*$$) += $1; }
|
charstring: CHAR { $$ = new string; (*$$) += $1; }
|
||||||
| charstring CHAR { $$ = $1; (*$$) += $2; }
|
| charstring CHAR { $$ = $1; (*$$) += $2; }
|
||||||
|
@ -573,6 +577,7 @@ anysymbol: SPACESYM { $$ = $1; }
|
||||||
| OPERANDSYM { $$ = $1; }
|
| OPERANDSYM { $$ = $1; }
|
||||||
| STARTSYM { $$ = $1; }
|
| STARTSYM { $$ = $1; }
|
||||||
| ENDSYM { $$ = $1; }
|
| ENDSYM { $$ = $1; }
|
||||||
|
| NEXT2SYM { $$ = $1; }
|
||||||
| BITSYM { $$ = $1; }
|
| BITSYM { $$ = $1; }
|
||||||
;
|
;
|
||||||
%%
|
%%
|
||||||
|
|
|
@ -165,6 +165,19 @@ public:
|
||||||
virtual void restoreXml(const Element *el,Translate *trans) {}
|
virtual void restoreXml(const Element *el,Translate *trans) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Next2InstructionValue : public PatternValue {
|
||||||
|
public:
|
||||||
|
Next2InstructionValue(void) {}
|
||||||
|
virtual intb getValue(ParserWalker &walker) const {
|
||||||
|
return (intb)AddrSpace::byteToAddress(walker.getN2addr().getOffset(),walker.getN2addr().getSpace()->getWordSize()); }
|
||||||
|
virtual TokenPattern genMinPattern(const vector<TokenPattern> &ops) const { return TokenPattern(); }
|
||||||
|
virtual TokenPattern genPattern(intb val) const { return TokenPattern(); }
|
||||||
|
virtual intb minValue(void) const { return (intb)0; }
|
||||||
|
virtual intb maxValue(void) const { return (intb)0; }
|
||||||
|
virtual void saveXml(ostream &s) const { s << "<next2_exp/>"; }
|
||||||
|
virtual void restoreXml(const Element *el,Translate *trans) {}
|
||||||
|
};
|
||||||
|
|
||||||
class Constructor; // Forward declaration
|
class Constructor; // Forward declaration
|
||||||
class OperandSymbol;
|
class OperandSymbol;
|
||||||
class OperandValue : public PatternValue {
|
class OperandValue : public PatternValue {
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -429,6 +429,9 @@ int4 find_symbol(void) {
|
||||||
case SleighSymbol::end_symbol:
|
case SleighSymbol::end_symbol:
|
||||||
yylval.endsym = (EndSymbol *)sym;
|
yylval.endsym = (EndSymbol *)sym;
|
||||||
return ENDSYM;
|
return ENDSYM;
|
||||||
|
case SleighSymbol::next2_symbol:
|
||||||
|
yylval.next2sym = (Next2Symbol *)sym;
|
||||||
|
return NEXT2SYM;
|
||||||
case SleighSymbol::subtable_symbol:
|
case SleighSymbol::subtable_symbol:
|
||||||
yylval.subtablesym = (SubtableSymbol *)sym;
|
yylval.subtablesym = (SubtableSymbol *)sym;
|
||||||
return SUBTABLESYM;
|
return SUBTABLESYM;
|
||||||
|
|
|
@ -252,6 +252,8 @@ void SymbolTable::restoreSymbolHeader(const Element *el)
|
||||||
sym = new StartSymbol();
|
sym = new StartSymbol();
|
||||||
else if (el->getName() == "end_sym_head")
|
else if (el->getName() == "end_sym_head")
|
||||||
sym = new EndSymbol();
|
sym = new EndSymbol();
|
||||||
|
else if (el->getName() == "next2_sym_head")
|
||||||
|
sym = new Next2Symbol();
|
||||||
else if (el->getName() == "subtable_sym_head")
|
else if (el->getName() == "subtable_sym_head")
|
||||||
sym = new SubtableSymbol();
|
sym = new SubtableSymbol();
|
||||||
else if (el->getName() == "flowdest_sym_head")
|
else if (el->getName() == "flowdest_sym_head")
|
||||||
|
@ -1254,6 +1256,70 @@ void EndSymbol::restoreXml(const Element *el,SleighBase *trans)
|
||||||
patexp->layClaim();
|
patexp->layClaim();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Next2Symbol::Next2Symbol(const string &nm,AddrSpace *cspc) : SpecificSymbol(nm)
|
||||||
|
|
||||||
|
{
|
||||||
|
const_space = cspc;
|
||||||
|
patexp = new Next2InstructionValue();
|
||||||
|
patexp->layClaim();
|
||||||
|
}
|
||||||
|
|
||||||
|
Next2Symbol::~Next2Symbol(void)
|
||||||
|
|
||||||
|
{
|
||||||
|
if (patexp != (PatternExpression *)0)
|
||||||
|
PatternExpression::release(patexp);
|
||||||
|
}
|
||||||
|
|
||||||
|
VarnodeTpl *Next2Symbol::getVarnode(void) const
|
||||||
|
|
||||||
|
{ // Return instruction offset after next instruction offset as a constant
|
||||||
|
ConstTpl spc(const_space);
|
||||||
|
ConstTpl off(ConstTpl::j_next2);
|
||||||
|
ConstTpl sz_zero;
|
||||||
|
return new VarnodeTpl(spc,off,sz_zero);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Next2Symbol::getFixedHandle(FixedHandle &hand,ParserWalker &walker) const
|
||||||
|
|
||||||
|
{
|
||||||
|
hand.space = walker.getCurSpace();
|
||||||
|
hand.offset_space = (AddrSpace *)0;
|
||||||
|
hand.offset_offset = walker.getN2addr().getOffset(); // Get instruction address after next instruction
|
||||||
|
hand.size = hand.space->getAddrSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Next2Symbol::print(ostream &s,ParserWalker &walker) const
|
||||||
|
|
||||||
|
{
|
||||||
|
intb val = (intb) walker.getN2addr().getOffset();
|
||||||
|
s << "0x" << hex << val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Next2Symbol::saveXml(ostream &s) const
|
||||||
|
|
||||||
|
{
|
||||||
|
s << "<next2_sym";
|
||||||
|
SleighSymbol::saveXmlHeader(s);
|
||||||
|
s << "/>\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
void Next2Symbol::saveXmlHeader(ostream &s) const
|
||||||
|
|
||||||
|
{
|
||||||
|
s << "<next2_sym_head";
|
||||||
|
SleighSymbol::saveXmlHeader(s);
|
||||||
|
s << "/>\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
void Next2Symbol::restoreXml(const Element *el,SleighBase *trans)
|
||||||
|
|
||||||
|
{
|
||||||
|
const_space = trans->getConstantSpace();
|
||||||
|
patexp = new Next2InstructionValue();
|
||||||
|
patexp->layClaim();
|
||||||
|
}
|
||||||
|
|
||||||
FlowDestSymbol::FlowDestSymbol(const string &nm,AddrSpace *cspc) : SpecificSymbol(nm)
|
FlowDestSymbol::FlowDestSymbol(const string &nm,AddrSpace *cspc) : SpecificSymbol(nm)
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
@ -25,7 +25,7 @@ class SleighSymbol {
|
||||||
public:
|
public:
|
||||||
enum symbol_type { space_symbol, token_symbol, userop_symbol, value_symbol, valuemap_symbol,
|
enum symbol_type { space_symbol, token_symbol, userop_symbol, value_symbol, valuemap_symbol,
|
||||||
name_symbol, varnode_symbol, varnodelist_symbol, operand_symbol,
|
name_symbol, varnode_symbol, varnodelist_symbol, operand_symbol,
|
||||||
start_symbol, end_symbol, subtable_symbol, macro_symbol, section_symbol,
|
start_symbol, end_symbol, next2_symbol, subtable_symbol, macro_symbol, section_symbol,
|
||||||
bitrange_symbol, context_symbol, epsilon_symbol, label_symbol,
|
bitrange_symbol, context_symbol, epsilon_symbol, label_symbol,
|
||||||
dummy_symbol };
|
dummy_symbol };
|
||||||
private:
|
private:
|
||||||
|
@ -391,6 +391,23 @@ public:
|
||||||
virtual void restoreXml(const Element *el,SleighBase *trans);
|
virtual void restoreXml(const Element *el,SleighBase *trans);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Next2Symbol : public SpecificSymbol {
|
||||||
|
AddrSpace *const_space;
|
||||||
|
PatternExpression *patexp;
|
||||||
|
public:
|
||||||
|
Next2Symbol(void) { patexp = (PatternExpression *)0; } // For use with restoreXml
|
||||||
|
Next2Symbol(const string &nm,AddrSpace *cspc);
|
||||||
|
virtual ~Next2Symbol(void);
|
||||||
|
virtual VarnodeTpl *getVarnode(void) const;
|
||||||
|
virtual PatternExpression *getPatternExpression(void) const { return patexp; }
|
||||||
|
virtual void getFixedHandle(FixedHandle &hand,ParserWalker &walker) const;
|
||||||
|
virtual void print(ostream &s,ParserWalker &walker) const;
|
||||||
|
virtual symbol_type getType(void) const { return next2_symbol; }
|
||||||
|
virtual void saveXml(ostream &s) const;
|
||||||
|
virtual void saveXmlHeader(ostream &s) const;
|
||||||
|
virtual void restoreXml(const Element *el,SleighBase *trans);
|
||||||
|
};
|
||||||
|
|
||||||
class FlowDestSymbol : public SpecificSymbol {
|
class FlowDestSymbol : public SpecificSymbol {
|
||||||
AddrSpace *const_space;
|
AddrSpace *const_space;
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -506,8 +506,8 @@ parameters in the actual p-code operation, or an exception will be thrown during
|
||||||
As with a <code><callfixup></code>, the <code><body></code> tag is fed straight to the SLEIGH semantic
|
As with a <code><callfixup></code>, the <code><body></code> tag is fed straight to the SLEIGH semantic
|
||||||
parser. It can refer to registers via their symbolic name defined in SLEIGH, it can refer to the operator parameters
|
parser. It can refer to registers via their symbolic name defined in SLEIGH, it can refer to the operator parameters
|
||||||
via their <code><input></code> or <code><output></code> names, and it can also refer to
|
via their <code><input></code> or <code><output></code> names, and it can also refer to
|
||||||
<code>inst_start</code> and <code>inst_next</code> as addresses describing the instruction containing the
|
<code>inst_start</code>, <code>inst_next</code> and <code>inst_next2</code> as addresses describing the instruction
|
||||||
<code>CALLOTHER</code>.
|
containing the <code>CALLOTHER</code>.
|
||||||
</para>
|
</para>
|
||||||
<example>
|
<example>
|
||||||
<programlisting>
|
<programlisting>
|
||||||
|
|
|
@ -1006,6 +1006,10 @@ We list all of the symbols that are predefined by SLEIGH.
|
||||||
<td><code>inst_next</code></td>
|
<td><code>inst_next</code></td>
|
||||||
<td>Offset of the address of the next instruction.</td>
|
<td>Offset of the address of the next instruction.</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>inst_next2</code></td>
|
||||||
|
<td>Offset of the address of the instruction after the next instruction.</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>epsilon</code></td>
|
<td><code>epsilon</code></td>
|
||||||
<td>A special identifier indicating an empty bit pattern.</td>
|
<td>A special identifier indicating an empty bit pattern.</td>
|
||||||
|
@ -1019,7 +1023,8 @@ and <emphasis>inst_next</emphasis>. These are family symbols which map
|
||||||
in the context of particular instruction to the integer offset of
|
in the context of particular instruction to the integer offset of
|
||||||
either the address of the instruction or the address of the next
|
either the address of the instruction or the address of the next
|
||||||
instruction respectively. These are used in any relative branching
|
instruction respectively. These are used in any relative branching
|
||||||
situation. The other symbols are rarely
|
situation. The <emphasis>inst_next2</emphasis> is intended for conditional
|
||||||
|
skip instruction situations. The remaining symbols are rarely
|
||||||
used. The <emphasis>const</emphasis> and <emphasis>unique</emphasis>
|
used. The <emphasis>const</emphasis> and <emphasis>unique</emphasis>
|
||||||
identifiers are address spaces. The <emphasis>epsilon</emphasis>
|
identifiers are address spaces. The <emphasis>epsilon</emphasis>
|
||||||
identifier is inherited from SLED and is a specific symbol equivalent
|
identifier is inherited from SLED and is a specific symbol equivalent
|
||||||
|
@ -2868,6 +2873,26 @@ the <emphasis>BRANCH</emphasis>, <emphasis>CBRANCH</emphasis>,
|
||||||
or <emphasis>CALL</emphasis> operation.
|
or <emphasis>CALL</emphasis> operation.
|
||||||
</para>
|
</para>
|
||||||
</sect4>
|
</sect4>
|
||||||
|
<sect4 id="sleigh_skip_instruction_branching">
|
||||||
|
<title>Skip Instruction Branching</title>
|
||||||
|
<para>>
|
||||||
|
Many processors have a conditional-skip-instruction which must branch over the next instruction
|
||||||
|
based upon some condition. The <emphasis>inst_next2</emphasis> symbol has been provided for
|
||||||
|
this purpose.
|
||||||
|
<informalexample>
|
||||||
|
<programlisting>
|
||||||
|
:skip.eq is opcode=10 {
|
||||||
|
if (zeroflag!=0) goto inst_next2;
|
||||||
|
}
|
||||||
|
</programlisting>
|
||||||
|
</informalexample>
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
In the example above, the branch address will be determined by adding the parsed-length of the next
|
||||||
|
instruction to the value of <emphasis>inst_next</emphasis> causing a branch over the next
|
||||||
|
instruction when the condition is satisfied.
|
||||||
|
</para>
|
||||||
|
</sect4>
|
||||||
<sect4 id="sleigh_bitrange_assign">
|
<sect4 id="sleigh_bitrange_assign">
|
||||||
<title>Bit Range Assignments</title>
|
<title>Bit Range Assignments</title>
|
||||||
<para>
|
<para>
|
||||||
|
@ -3439,7 +3464,8 @@ by the condition.
|
||||||
<para>
|
<para>
|
||||||
Because the <emphasis role="bold">delayslot</emphasis> directive
|
Because the <emphasis role="bold">delayslot</emphasis> directive
|
||||||
combines two or more instructions into one, the meaning of the
|
combines two or more instructions into one, the meaning of the
|
||||||
symbol <emphasis>inst_next</emphasis> becomes ambiguous. It is not
|
symbol <emphasis>inst_next</emphasis> and <emphasis>inst_next2</emphasis>
|
||||||
|
become ambiguous. It is not
|
||||||
clear anymore what exactly the “next instruction” is. SLEIGH uses the
|
clear anymore what exactly the “next instruction” is. SLEIGH uses the
|
||||||
following conventions for interpreting
|
following conventions for interpreting
|
||||||
an <emphasis>inst_next</emphasis> symbol. If it is used in the
|
an <emphasis>inst_next</emphasis> symbol. If it is used in the
|
||||||
|
@ -3447,7 +3473,11 @@ semantic section, the symbol refers to the address of the instruction
|
||||||
after any instructions in the delay slot. However, if it is used in a
|
after any instructions in the delay slot. However, if it is used in a
|
||||||
disassembly action, the <emphasis>inst_next</emphasis> symbol refers
|
disassembly action, the <emphasis>inst_next</emphasis> symbol refers
|
||||||
to the address of the instruction immediately after the first
|
to the address of the instruction immediately after the first
|
||||||
instruction, even if there is a delay slot.
|
instruction, even if there is a delay slot. The use of
|
||||||
|
the <emphasis>inst_next2</emphasis> symbol may be inappropriate in
|
||||||
|
conjunction with delayslot use. While the next instruction address
|
||||||
|
is identified by <emphasis>inst_next</emphasis>, the length of the
|
||||||
|
next instruction ignores any delayslots it may have.
|
||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
|
@ -349,9 +349,10 @@ specific_symbol[String purpose] returns [SpecificSymbol symbol]
|
||||||
: ^(OP_IDENTIFIER s=.) {
|
: ^(OP_IDENTIFIER s=.) {
|
||||||
SleighSymbol sym = pcode.findSymbol($s.getText());
|
SleighSymbol sym = pcode.findSymbol($s.getText());
|
||||||
if (sym == null) {
|
if (sym == null) {
|
||||||
unknownSymbolError($s.getText(), find($s), "start, end, operand, epsilon, or varnode", purpose);
|
unknownSymbolError($s.getText(), find($s), "start, end, next2, operand, epsilon, or varnode", purpose);
|
||||||
} else if(sym.getType() != symbol_type.start_symbol
|
} else if(sym.getType() != symbol_type.start_symbol
|
||||||
&& sym.getType() != symbol_type.end_symbol
|
&& sym.getType() != symbol_type.end_symbol
|
||||||
|
&& sym.getType() != symbol_type.next2_symbol
|
||||||
&& sym.getType() != symbol_type.operand_symbol
|
&& sym.getType() != symbol_type.operand_symbol
|
||||||
&& sym.getType() != symbol_type.epsilon_symbol
|
&& sym.getType() != symbol_type.epsilon_symbol
|
||||||
&& sym.getType() != symbol_type.varnode_symbol) {
|
&& sym.getType() != symbol_type.varnode_symbol) {
|
||||||
|
@ -839,7 +840,7 @@ pattern_symbol[String purpose] returns [PatternExpression expr]
|
||||||
: ^(OP_IDENTIFIER s=.) {
|
: ^(OP_IDENTIFIER s=.) {
|
||||||
SleighSymbol sym = sc.findSymbol($s.getText());
|
SleighSymbol sym = sc.findSymbol($s.getText());
|
||||||
if (sym == null) {
|
if (sym == null) {
|
||||||
unknownSymbolError($s.getText(), find($s), "start, end, operand, epsilon, or varnode", purpose);
|
unknownSymbolError($s.getText(), find($s), "start, end, next2, operand, epsilon, or varnode", purpose);
|
||||||
} else if(sym.getType() == symbol_type.operand_symbol) {
|
} else if(sym.getType() == symbol_type.operand_symbol) {
|
||||||
OperandSymbol os = (OperandSymbol) sym;
|
OperandSymbol os = (OperandSymbol) sym;
|
||||||
if (os.getDefiningSymbol() != null && os.getDefiningSymbol().getType() == symbol_type.subtable_symbol) {
|
if (os.getDefiningSymbol() != null && os.getDefiningSymbol().getType() == symbol_type.subtable_symbol) {
|
||||||
|
@ -848,6 +849,7 @@ pattern_symbol[String purpose] returns [PatternExpression expr]
|
||||||
$expr = os.getPatternExpression();
|
$expr = os.getPatternExpression();
|
||||||
} else if(sym.getType() == symbol_type.start_symbol
|
} else if(sym.getType() == symbol_type.start_symbol
|
||||||
|| sym.getType() == symbol_type.end_symbol
|
|| sym.getType() == symbol_type.end_symbol
|
||||||
|
|| sym.getType() == symbol_type.next2_symbol
|
||||||
|| sym.getType() == symbol_type.epsilon_symbol
|
|| sym.getType() == symbol_type.epsilon_symbol
|
||||||
|| sym.getType() == symbol_type.varnode_symbol) {
|
|| sym.getType() == symbol_type.varnode_symbol) {
|
||||||
SpecificSymbol ss = (SpecificSymbol) sym;
|
SpecificSymbol ss = (SpecificSymbol) sym;
|
||||||
|
@ -864,7 +866,7 @@ pattern_symbol[String purpose] returns [PatternExpression expr]
|
||||||
reportError(find($s), "Global symbol '" + sym.getName() + "' is not allowed in action expression");
|
reportError(find($s), "Global symbol '" + sym.getName() + "' is not allowed in action expression");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
wrongSymbolTypeError(sym, find($s), "start, end, operand, epsilon, or varnode", purpose);
|
wrongSymbolTypeError(sym, find($s), "start, end, next2, operand, epsilon, or varnode", purpose);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
| t=OP_WILDCARD {
|
| t=OP_WILDCARD {
|
||||||
|
@ -877,9 +879,10 @@ pattern_symbol2[String purpose] returns [PatternExpression expr]
|
||||||
: ^(OP_IDENTIFIER s=.) {
|
: ^(OP_IDENTIFIER s=.) {
|
||||||
SleighSymbol sym = sc.findSymbol($s.getText());
|
SleighSymbol sym = sc.findSymbol($s.getText());
|
||||||
if (sym == null) {
|
if (sym == null) {
|
||||||
unknownSymbolError($s.getText(), find($s), "start, end, operand, epsilon, or varnode", purpose);
|
unknownSymbolError($s.getText(), find($s), "start, end, next2, operand, epsilon, or varnode", purpose);
|
||||||
} else if(sym.getType() == symbol_type.start_symbol
|
} else if(sym.getType() == symbol_type.start_symbol
|
||||||
|| sym.getType() == symbol_type.end_symbol
|
|| sym.getType() == symbol_type.end_symbol
|
||||||
|
|| sym.getType() == symbol_type.next2_symbol
|
||||||
|| sym.getType() == symbol_type.operand_symbol
|
|| sym.getType() == symbol_type.operand_symbol
|
||||||
|| sym.getType() == symbol_type.epsilon_symbol
|
|| sym.getType() == symbol_type.epsilon_symbol
|
||||||
|| sym.getType() == symbol_type.varnode_symbol) {
|
|| sym.getType() == symbol_type.varnode_symbol) {
|
||||||
|
@ -893,7 +896,7 @@ pattern_symbol2[String purpose] returns [PatternExpression expr]
|
||||||
FamilySymbol z = (FamilySymbol) sym;
|
FamilySymbol z = (FamilySymbol) sym;
|
||||||
$expr = z.getPatternValue();
|
$expr = z.getPatternValue();
|
||||||
} else {
|
} else {
|
||||||
wrongSymbolTypeError(sym, find($s), "start, end, operand, epsilon, or varnode", purpose);
|
wrongSymbolTypeError(sym, find($s), "start, end, next2, operand, epsilon, or varnode", purpose);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
| t=OP_WILDCARD {
|
| t=OP_WILDCARD {
|
||||||
|
@ -922,7 +925,7 @@ cstatement[VectorSTL<ContextChange> r]
|
||||||
} else if(sym.getType() == symbol_type.context_symbol) {
|
} else if(sym.getType() == symbol_type.context_symbol) {
|
||||||
ContextSymbol t = (ContextSymbol) sym;
|
ContextSymbol t = (ContextSymbol) sym;
|
||||||
if (!sc.contextMod(r, t, e)) {
|
if (!sc.contextMod(r, t, e)) {
|
||||||
reportError(find($id), "Cannot use 'inst_next' to set context variable: '" + t.getName() + "'");
|
reportError(find($id), "Cannot use 'inst_next' or 'inst_next2' to set context variable: '" + t.getName() + "'");
|
||||||
}
|
}
|
||||||
} else if(sym.getType() == symbol_type.operand_symbol) {
|
} else if(sym.getType() == symbol_type.operand_symbol) {
|
||||||
OperandSymbol t = (OperandSymbol) sym;
|
OperandSymbol t = (OperandSymbol) sym;
|
||||||
|
@ -950,6 +953,7 @@ cstatement[VectorSTL<ContextChange> r]
|
||||||
|| sym.getType() == symbol_type.varnodelist_symbol
|
|| sym.getType() == symbol_type.varnodelist_symbol
|
||||||
|| sym.getType() == symbol_type.start_symbol
|
|| sym.getType() == symbol_type.start_symbol
|
||||||
|| sym.getType() == symbol_type.end_symbol
|
|| sym.getType() == symbol_type.end_symbol
|
||||||
|
|| sym.getType() == symbol_type.next2_symbol
|
||||||
|| sym.getType() == symbol_type.operand_symbol
|
|| sym.getType() == symbol_type.operand_symbol
|
||||||
|| sym.getType() == symbol_type.epsilon_symbol
|
|| sym.getType() == symbol_type.epsilon_symbol
|
||||||
|| sym.getType() == symbol_type.varnode_symbol) {
|
|| sym.getType() == symbol_type.varnode_symbol) {
|
||||||
|
@ -1176,10 +1180,11 @@ assignment returns [VectorSTL<OpTpl> value]
|
||||||
$value = pcode.newOutput(find(id), false, e, $id.getText());
|
$value = pcode.newOutput(find(id), false, e, $id.getText());
|
||||||
} else if(sym.getType() != symbol_type.start_symbol
|
} else if(sym.getType() != symbol_type.start_symbol
|
||||||
&& sym.getType() != symbol_type.end_symbol
|
&& sym.getType() != symbol_type.end_symbol
|
||||||
|
&& sym.getType() != symbol_type.next2_symbol
|
||||||
&& sym.getType() != symbol_type.operand_symbol
|
&& sym.getType() != symbol_type.operand_symbol
|
||||||
&& sym.getType() != symbol_type.epsilon_symbol
|
&& sym.getType() != symbol_type.epsilon_symbol
|
||||||
&& sym.getType() != symbol_type.varnode_symbol) {
|
&& sym.getType() != symbol_type.varnode_symbol) {
|
||||||
wrongSymbolTypeError(sym, find(id), "start, end, operand, epsilon, or varnode", "assignment");
|
wrongSymbolTypeError(sym, find(id), "start, end, next2, operand, epsilon, or varnode", "assignment");
|
||||||
} else {
|
} else {
|
||||||
VarnodeTpl v = ((SpecificSymbol) sym).getVarnode();
|
VarnodeTpl v = ((SpecificSymbol) sym).getVarnode();
|
||||||
e.setOutput(find(t), v);
|
e.setOutput(find(t), v);
|
||||||
|
@ -1309,7 +1314,9 @@ jump_symbol[String purpose] returns [VarnodeTpl value]
|
||||||
SleighSymbol sym = pcode.findSymbol($s.getText());
|
SleighSymbol sym = pcode.findSymbol($s.getText());
|
||||||
if (sym == null) {
|
if (sym == null) {
|
||||||
unknownSymbolError($s.getText(), find($s), "start, end, or operand", purpose);
|
unknownSymbolError($s.getText(), find($s), "start, end, or operand", purpose);
|
||||||
} else if(sym.getType() == symbol_type.start_symbol || sym.getType() == symbol_type.end_symbol) {
|
} else if (sym.getType() == symbol_type.start_symbol ||
|
||||||
|
sym.getType() == symbol_type.end_symbol ||
|
||||||
|
sym.getType() == symbol_type.next2_symbol) {
|
||||||
SpecificSymbol ss = (SpecificSymbol) sym;
|
SpecificSymbol ss = (SpecificSymbol) sym;
|
||||||
$value = new VarnodeTpl(find($s), new ConstTpl(ConstTpl.const_type.j_curspace),
|
$value = new VarnodeTpl(find($s), new ConstTpl(ConstTpl.const_type.j_curspace),
|
||||||
ss.getVarnode().getOffset(),
|
ss.getVarnode().getOffset(),
|
||||||
|
@ -1489,6 +1496,7 @@ expr_apply returns [Object value]
|
||||||
}
|
}
|
||||||
} else if(sym.getType() == symbol_type.start_symbol
|
} else if(sym.getType() == symbol_type.start_symbol
|
||||||
|| sym.getType() == symbol_type.end_symbol
|
|| sym.getType() == symbol_type.end_symbol
|
||||||
|
|| sym.getType() == symbol_type.next2_symbol
|
||||||
|| sym.getType() == symbol_type.operand_symbol
|
|| sym.getType() == symbol_type.operand_symbol
|
||||||
|| sym.getType() == symbol_type.epsilon_symbol
|
|| sym.getType() == symbol_type.epsilon_symbol
|
||||||
|| sym.getType() == symbol_type.varnode_symbol) {
|
|| sym.getType() == symbol_type.varnode_symbol) {
|
||||||
|
|
|
@ -573,6 +573,10 @@ public class SleighAssemblerBuilder implements AssemblerBuilder {
|
||||||
else if (sym instanceof EndSymbol) {
|
else if (sym instanceof EndSymbol) {
|
||||||
// Ignore. We handle inst_next in semantic processing
|
// Ignore. We handle inst_next in semantic processing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else if (sym instanceof Next2Symbol) {
|
||||||
|
// Ignore. We handle inst_next2 in semantic processing
|
||||||
|
}
|
||||||
else if (sym instanceof UseropSymbol) {
|
else if (sym instanceof UseropSymbol) {
|
||||||
// Ignore. We don't do pcode.
|
// Ignore. We don't do pcode.
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,77 @@
|
||||||
|
/* ###
|
||||||
|
* 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.assembler.sleigh.expr;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import ghidra.app.plugin.assembler.sleigh.sem.*;
|
||||||
|
import ghidra.app.plugin.processors.sleigh.expression.EndInstructionValue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* "Solves" expressions of {@code inst_next2}
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Works like the constant solver, but takes the value of {@code inst_next}, which is given by the
|
||||||
|
* assembly address and the resulting instruction length.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* <b>NOTE:</b> This solver requires backfill, since the value of {@code inst_next2} is not known
|
||||||
|
* until possible prefixes have been considered.
|
||||||
|
*/
|
||||||
|
public class Next2InstructionValueSolver extends AbstractExpressionSolver<EndInstructionValue> {
|
||||||
|
|
||||||
|
public Next2InstructionValueSolver() {
|
||||||
|
super(EndInstructionValue.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AssemblyResolution solve(EndInstructionValue iv, MaskedLong goal, Map<String, Long> vals,
|
||||||
|
AssemblyResolvedPatterns cur, Set<SolverHint> hints, String description) {
|
||||||
|
throw new AssertionError(
|
||||||
|
"INTERNAL: Should never be asked to solve for " + AssemblyTreeResolver.INST_NEXT2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MaskedLong getValue(EndInstructionValue iv, Map<String, Long> vals,
|
||||||
|
AssemblyResolvedPatterns cur) throws NeedsBackfillException {
|
||||||
|
Long instNext = vals.get(AssemblyTreeResolver.INST_NEXT2);
|
||||||
|
if (instNext == null) {
|
||||||
|
throw new NeedsBackfillException(AssemblyTreeResolver.INST_NEXT2);
|
||||||
|
}
|
||||||
|
return MaskedLong.fromLong(instNext);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getInstructionLength(EndInstructionValue iv) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MaskedLong valueForResolution(EndInstructionValue exp, Map<String, Long> vals,
|
||||||
|
AssemblyResolvedPatterns rc) {
|
||||||
|
Long instNext = vals.get(AssemblyTreeResolver.INST_NEXT2);
|
||||||
|
if (instNext == null) {
|
||||||
|
/**
|
||||||
|
* This method is used in forward state construction, so just leave unknown. This may
|
||||||
|
* cause unresolvable trees to get generated, but we can't know that until we try to
|
||||||
|
* resolve them.
|
||||||
|
*/
|
||||||
|
return MaskedLong.UNKS;
|
||||||
|
}
|
||||||
|
return MaskedLong.fromLong(instNext);
|
||||||
|
}
|
||||||
|
}
|
|
@ -53,6 +53,7 @@ public class RecursiveDescentSolver {
|
||||||
new ContextFieldSolver().register(this);
|
new ContextFieldSolver().register(this);
|
||||||
new DivExpressionSolver().register(this);
|
new DivExpressionSolver().register(this);
|
||||||
new EndInstructionValueSolver().register(this);
|
new EndInstructionValueSolver().register(this);
|
||||||
|
new Next2InstructionValueSolver().register(this);
|
||||||
new LeftShiftExpressionSolver().register(this);
|
new LeftShiftExpressionSolver().register(this);
|
||||||
new MinusExpressionSolver().register(this);
|
new MinusExpressionSolver().register(this);
|
||||||
new MultExpressionSolver().register(this);
|
new MultExpressionSolver().register(this);
|
||||||
|
|
|
@ -78,6 +78,9 @@ public abstract class AbstractExpressionMatcher<T extends PatternExpression>
|
||||||
if (a instanceof EndInstructionValue) {
|
if (a instanceof EndInstructionValue) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (a instanceof Next2InstructionValue) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if (a instanceof StartInstructionValue) {
|
if (a instanceof StartInstructionValue) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,6 +54,7 @@ public class AssemblyTreeResolver {
|
||||||
|
|
||||||
public static final String INST_START = "inst_start";
|
public static final String INST_START = "inst_start";
|
||||||
public static final String INST_NEXT = "inst_next";
|
public static final String INST_NEXT = "inst_next";
|
||||||
|
public static final String INST_NEXT2 = "inst_next2";
|
||||||
|
|
||||||
protected final SleighLanguage lang;
|
protected final SleighLanguage lang;
|
||||||
protected final Address at;
|
protected final Address at;
|
||||||
|
@ -195,6 +196,8 @@ public class AssemblyTreeResolver {
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
vals.put(INST_NEXT, at.add(rc.getInstructionLength()).getAddressableWordOffset());
|
vals.put(INST_NEXT, at.add(rc.getInstructionLength()).getAddressableWordOffset());
|
||||||
|
// inst_next2 use not really supported
|
||||||
|
vals.put(INST_NEXT2, at.add(rc.getInstructionLength()).getAddressableWordOffset());
|
||||||
DBG.println("Backfilling: " + rc);
|
DBG.println("Backfilling: " + rc);
|
||||||
AssemblyResolution ar = rc.backfill(SOLVER, vals);
|
AssemblyResolution ar = rc.backfill(SOLVER, vals);
|
||||||
DBG.println("Backfilled final: " + ar);
|
DBG.println("Backfilled final: " + ar);
|
||||||
|
|
|
@ -210,6 +210,12 @@ public class ParserWalker {
|
||||||
return context.getNaddr();
|
return context.getNaddr();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Address getN2addr() {
|
||||||
|
if (cross_context != null)
|
||||||
|
return cross_context.getN2addr();
|
||||||
|
return context.getN2addr();
|
||||||
|
}
|
||||||
|
|
||||||
public AddressSpace getCurSpace() {
|
public AddressSpace getCurSpace() {
|
||||||
return context.getCurSpace();
|
return context.getCurSpace();
|
||||||
}
|
}
|
||||||
|
|
|
@ -246,7 +246,7 @@ public abstract class PcodeEmit {
|
||||||
if (opcode == PcodeOp.BRANCH) {
|
if (opcode == PcodeOp.BRANCH) {
|
||||||
int offsetType = inputs[0].getOffset().getType();
|
int offsetType = inputs[0].getOffset().getType();
|
||||||
if (offsetType == ConstTpl.J_RELATIVE || offsetType == ConstTpl.J_START ||
|
if (offsetType == ConstTpl.J_RELATIVE || offsetType == ConstTpl.J_START ||
|
||||||
offsetType == ConstTpl.J_NEXT) {
|
offsetType == ConstTpl.J_NEXT || offsetType == ConstTpl.J_NEXT2) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
OpTpl callopt = new OpTpl(PcodeOp.CALL, null, inputs);
|
OpTpl callopt = new OpTpl(PcodeOp.CALL, null, inputs);
|
||||||
|
@ -269,7 +269,7 @@ public abstract class PcodeEmit {
|
||||||
else if (opcode == PcodeOp.CBRANCH) {
|
else if (opcode == PcodeOp.CBRANCH) {
|
||||||
int offsetType = inputs[0].getOffset().getType();
|
int offsetType = inputs[0].getOffset().getType();
|
||||||
if (offsetType == ConstTpl.J_RELATIVE || offsetType == ConstTpl.J_START ||
|
if (offsetType == ConstTpl.J_RELATIVE || offsetType == ConstTpl.J_START ||
|
||||||
offsetType == ConstTpl.J_NEXT) {
|
offsetType == ConstTpl.J_NEXT || offsetType == ConstTpl.J_NEXT2) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -326,7 +326,7 @@ public abstract class PcodeEmit {
|
||||||
if (opcode == PcodeOp.BRANCH || opcode == PcodeOp.CALL) {
|
if (opcode == PcodeOp.BRANCH || opcode == PcodeOp.CALL) {
|
||||||
int offsetType = inputs[0].getOffset().getType();
|
int offsetType = inputs[0].getOffset().getType();
|
||||||
if (offsetType == ConstTpl.J_RELATIVE || offsetType == ConstTpl.J_START ||
|
if (offsetType == ConstTpl.J_RELATIVE || offsetType == ConstTpl.J_START ||
|
||||||
offsetType == ConstTpl.J_NEXT) {
|
offsetType == ConstTpl.J_NEXT || offsetType == ConstTpl.J_NEXT2) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -89,7 +89,6 @@ public class SleighInstructionPrototype implements InstructionPrototype {
|
||||||
private final static Address[] emptyFlow = new Address[0];
|
private final static Address[] emptyFlow = new Address[0];
|
||||||
|
|
||||||
private ContextCache contextCache;
|
private ContextCache contextCache;
|
||||||
// private InstructionContext instructionContextCache;
|
|
||||||
private int length;
|
private int length;
|
||||||
private ConstructState rootState;
|
private ConstructState rootState;
|
||||||
private ConstructState mnemonicState; // state for print mnemonic
|
private ConstructState mnemonicState; // state for print mnemonic
|
||||||
|
@ -236,6 +235,9 @@ public class SleighInstructionPrototype implements InstructionPrototype {
|
||||||
if (destType == ConstTpl.J_NEXT) {
|
if (destType == ConstTpl.J_NEXT) {
|
||||||
flags = BRANCH_TO_END;
|
flags = BRANCH_TO_END;
|
||||||
}
|
}
|
||||||
|
else if (destType == ConstTpl.J_NEXT2) {
|
||||||
|
flags = JUMPOUT;
|
||||||
|
}
|
||||||
else if ((destType != ConstTpl.J_START) && (destType != ConstTpl.J_RELATIVE)) {
|
else if ((destType != ConstTpl.J_START) && (destType != ConstTpl.J_RELATIVE)) {
|
||||||
flags = JUMPOUT;
|
flags = JUMPOUT;
|
||||||
}
|
}
|
||||||
|
@ -674,6 +676,9 @@ public class SleighInstructionPrototype implements InstructionPrototype {
|
||||||
Address addr = getHandleAddr(hand, parsecontext.getAddr().getAddressSpace());
|
Address addr = getHandleAddr(hand, parsecontext.getAddr().getAddressSpace());
|
||||||
res.add(addr);
|
res.add(addr);
|
||||||
}
|
}
|
||||||
|
else if (rec.op.getInput()[0].getOffset().getType() == ConstTpl.J_NEXT2) {
|
||||||
|
res.add(parsecontext.getN2addr());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,8 +21,7 @@ import ghidra.app.plugin.processors.sleigh.symbol.OperandSymbol;
|
||||||
import ghidra.app.plugin.processors.sleigh.symbol.TripleSymbol;
|
import ghidra.app.plugin.processors.sleigh.symbol.TripleSymbol;
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.lang.*;
|
import ghidra.program.model.lang.*;
|
||||||
import ghidra.program.model.mem.MemBuffer;
|
import ghidra.program.model.mem.*;
|
||||||
import ghidra.program.model.mem.MemoryAccessException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -33,8 +32,9 @@ import ghidra.program.model.mem.MemoryAccessException;
|
||||||
|
|
||||||
public class SleighParserContext implements ParserContext {
|
public class SleighParserContext implements ParserContext {
|
||||||
private MemBuffer memBuffer;
|
private MemBuffer memBuffer;
|
||||||
private Address addr; // Address of start of instruction
|
private Address addr; // Address of start of instruction (inst_start)
|
||||||
private Address nextInstrAddr; // Address of next instruction
|
private Address nextInstrAddr; // Address of next instruction (inst_next)
|
||||||
|
private Address next2InstAddr; // Address of instruction after next instruction (inst_next2)
|
||||||
private Address refAddr; // corresponds to inst_ref for call-fixup use
|
private Address refAddr; // corresponds to inst_ref for call-fixup use
|
||||||
private Address destAddr; // corresponds to inst_dest for call-fixup use
|
private Address destAddr; // corresponds to inst_dest for call-fixup use
|
||||||
private SleighInstructionPrototype prototype;
|
private SleighInstructionPrototype prototype;
|
||||||
|
@ -71,7 +71,8 @@ public class SleighParserContext implements ParserContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for building precompiled templates
|
* Constructor for building precompiled templates.
|
||||||
|
* NOTE: This form does not support use of <code>inst_next2</next>.
|
||||||
* @param aAddr = address to which 'inst_start' resolves
|
* @param aAddr = address to which 'inst_start' resolves
|
||||||
* @param nAddr = address to which 'inst_next' resolves
|
* @param nAddr = address to which 'inst_next' resolves
|
||||||
* @param rAddr = special address associated with original call
|
* @param rAddr = special address associated with original call
|
||||||
|
@ -172,22 +173,99 @@ public class SleighParserContext implements ParserContext {
|
||||||
return handle;
|
return handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get address of current instruction
|
||||||
|
* @return address of current instruction
|
||||||
|
*/
|
||||||
public Address getAddr() {
|
public Address getAddr() {
|
||||||
return addr;
|
return addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get address of instruction after current instruction. This may return null if this context
|
||||||
|
* instance does not support use of {@code inst_next} or next address falls beyond end of
|
||||||
|
* address space.
|
||||||
|
* @return address of next instruction or null
|
||||||
|
*/
|
||||||
public Address getNaddr() {
|
public Address getNaddr() {
|
||||||
return nextInstrAddr;
|
return nextInstrAddr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get address of instruction after the next instruction. This may return {@link #getNaddr()}
|
||||||
|
* if this context instance does not support use of {@code inst_next2} or parse of next
|
||||||
|
* instruction fails.
|
||||||
|
* @return address of instruction after the next instruction or null
|
||||||
|
*/
|
||||||
|
public Address getN2addr() {
|
||||||
|
if (next2InstAddr != null) {
|
||||||
|
return next2InstAddr;
|
||||||
|
}
|
||||||
|
next2InstAddr = computeNext2Address();
|
||||||
|
if (next2InstAddr == null) {
|
||||||
|
// unsupported use of inst_next2 or parse failure on next instruction
|
||||||
|
// returns same as inst_next
|
||||||
|
next2InstAddr = nextInstrAddr;
|
||||||
|
}
|
||||||
|
return next2InstAddr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the address after the next instruction (inst_next2). The length of next instruction
|
||||||
|
* based on attempted parse of next instruction and does not consider any delayslot use.
|
||||||
|
* The current instructions context is used during the parse.
|
||||||
|
* @return address after the next instruction or null if unable/failed to determine
|
||||||
|
*/
|
||||||
|
private Address computeNext2Address() {
|
||||||
|
if (memBuffer == null || nextInstrAddr == null) {
|
||||||
|
return null; // not supported without memBuffer for parse
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Address nextAddr = nextInstrAddr;
|
||||||
|
Language language = prototype.getLanguage();
|
||||||
|
|
||||||
|
// limitation: assumes same context as current instruction
|
||||||
|
ProcessorContextImpl ctx = new ProcessorContextImpl(language);
|
||||||
|
RegisterValue ctxVal = getContextRegisterValue();
|
||||||
|
if (ctxVal != null) {
|
||||||
|
ctx.setRegisterValue(ctxVal);
|
||||||
|
}
|
||||||
|
|
||||||
|
int offset = (int) nextAddr.subtract(addr);
|
||||||
|
MemBuffer nearbymem = new WrappedMemBuffer(memBuffer, offset);
|
||||||
|
|
||||||
|
SleighInstructionPrototype proto =
|
||||||
|
(SleighInstructionPrototype) language.parse(nearbymem, ctx, true);
|
||||||
|
|
||||||
|
return nextAddr.addNoWrap(proto.getLength());
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get address space containing current instruction
|
||||||
|
* @return address space containing current instruction
|
||||||
|
*/
|
||||||
public AddressSpace getCurSpace() {
|
public AddressSpace getCurSpace() {
|
||||||
return addr.getAddressSpace();
|
return addr.getAddressSpace();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get constant address space
|
||||||
|
* @return constant address space
|
||||||
|
*/
|
||||||
public AddressSpace getConstSpace() {
|
public AddressSpace getConstSpace() {
|
||||||
return constantSpace;
|
return constantSpace;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get memory buffer for current instruction which may also be used to parse next instruction
|
||||||
|
* or delay slot instructions.
|
||||||
|
* @return memory buffer for current instruction
|
||||||
|
*/
|
||||||
public MemBuffer getMemBuffer() {
|
public MemBuffer getMemBuffer() {
|
||||||
return memBuffer;
|
return memBuffer;
|
||||||
}
|
}
|
||||||
|
@ -251,6 +329,44 @@ public class SleighParserContext implements ParserContext {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the processor context value as a RegisterValue
|
||||||
|
* @return processor context value
|
||||||
|
*/
|
||||||
|
public RegisterValue getContextRegisterValue() {
|
||||||
|
|
||||||
|
Register baseContextRegister = prototype.getLanguage().getContextBaseRegister();
|
||||||
|
if (baseContextRegister == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert context int words to byte array for RegisterValue use
|
||||||
|
int ctxByteLen = baseContextRegister.getMinimumByteSize();
|
||||||
|
byte[] ctxValueBytes = new byte[ctxByteLen];
|
||||||
|
|
||||||
|
for (int i = 0; i < context.length; i++) {
|
||||||
|
int word = context[i];
|
||||||
|
for (int n = 3; n >= 0; --n) {
|
||||||
|
int byteIndex = (i * 4) + n;
|
||||||
|
setByte(ctxValueBytes, byteIndex, (byte) word);
|
||||||
|
word >>= 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// append mask to value array for RegisterValue use
|
||||||
|
byte[] ctxValueMaskBytes = new byte[2 * ctxByteLen];
|
||||||
|
Arrays.fill(ctxValueMaskBytes, 0, ctxByteLen, (byte) 0xff);
|
||||||
|
System.arraycopy(ctxValueBytes, 0, ctxValueMaskBytes, ctxByteLen, ctxByteLen);
|
||||||
|
|
||||||
|
return new RegisterValue(baseContextRegister, ctxValueMaskBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setByte(byte[] bytes, int index, byte b) {
|
||||||
|
if (index < bytes.length) {
|
||||||
|
bytes[index] = b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get bytes from context into an int
|
* Get bytes from context into an int
|
||||||
* @param bytestart is the index of the first byte to fetch
|
* @param bytestart is the index of the first byte to fetch
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
/* ###
|
||||||
|
* 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.expression;
|
||||||
|
|
||||||
|
import ghidra.app.plugin.processors.sleigh.ParserWalker;
|
||||||
|
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
|
||||||
|
import ghidra.program.model.address.Address;
|
||||||
|
import ghidra.program.model.mem.MemoryAccessException;
|
||||||
|
import ghidra.xml.XmlPullParser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* The integer offset of the address following the current instruction
|
||||||
|
*/
|
||||||
|
public class Next2InstructionValue extends PatternValue {
|
||||||
|
private static final int HASH = "[inst_next2]".hashCode();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return HASH;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
return obj instanceof Next2InstructionValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long minValue() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long maxValue() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getValue(ParserWalker walker) throws MemoryAccessException {
|
||||||
|
Address addr = walker.getN2addr();
|
||||||
|
return addr.getAddressableWordOffset();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void restoreXml(XmlPullParser parser, SleighLanguage lang) {
|
||||||
|
parser.discardSubTree("next2_exp");
|
||||||
|
// Nothing to do
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "[inst_next2]";
|
||||||
|
}
|
||||||
|
}
|
|
@ -51,6 +51,8 @@ public abstract class PatternExpression {
|
||||||
res = new StartInstructionValue();
|
res = new StartInstructionValue();
|
||||||
else if (nm.equals("end_exp"))
|
else if (nm.equals("end_exp"))
|
||||||
res = new EndInstructionValue();
|
res = new EndInstructionValue();
|
||||||
|
else if (nm.equals("next2_exp"))
|
||||||
|
res = new Next2InstructionValue();
|
||||||
else if (nm.equals("plus_exp"))
|
else if (nm.equals("plus_exp"))
|
||||||
res = new PlusExpression();
|
res = new PlusExpression();
|
||||||
else if (nm.equals("sub_exp"))
|
else if (nm.equals("sub_exp"))
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
/* ###
|
||||||
|
* 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.symbol;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import ghidra.app.plugin.processors.sleigh.*;
|
||||||
|
import ghidra.app.plugin.processors.sleigh.expression.Next2InstructionValue;
|
||||||
|
import ghidra.app.plugin.processors.sleigh.expression.PatternExpression;
|
||||||
|
import ghidra.program.model.mem.MemoryAccessException;
|
||||||
|
import ghidra.xml.XmlElement;
|
||||||
|
import ghidra.xml.XmlPullParser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Symbol with semantic value equal to offset of address immediately
|
||||||
|
* after the next instruction (inst_next2)
|
||||||
|
*/
|
||||||
|
public class Next2Symbol extends SpecificSymbol {
|
||||||
|
|
||||||
|
private PatternExpression patexp;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PatternExpression getPatternExpression() {
|
||||||
|
return patexp;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void getFixedHandle(FixedHandle hand, ParserWalker walker) {
|
||||||
|
hand.space = walker.getCurSpace();
|
||||||
|
hand.offset_space = null;
|
||||||
|
hand.offset_offset = walker.getN2addr().getOffset();
|
||||||
|
hand.size = hand.space.getPointerSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String print(ParserWalker walker) throws MemoryAccessException {
|
||||||
|
long val = walker.getN2addr().getOffset();
|
||||||
|
return "0x"+Long.toHexString(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void printList(ParserWalker walker, ArrayList<Object> list) {
|
||||||
|
list.add(walker.getParentHandle());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void restoreXml(XmlPullParser parser, SleighLanguage sleigh) {
|
||||||
|
XmlElement element = parser.start("next2_sym");
|
||||||
|
patexp = new Next2InstructionValue();
|
||||||
|
parser.end(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -19,6 +19,8 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.plugin.processors.sleigh.symbol;
|
package ghidra.app.plugin.processors.sleigh.symbol;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
import ghidra.app.plugin.processors.sleigh.SleighException;
|
import ghidra.app.plugin.processors.sleigh.SleighException;
|
||||||
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
|
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
|
||||||
import ghidra.program.model.lang.UnknownInstructionException;
|
import ghidra.program.model.lang.UnknownInstructionException;
|
||||||
|
@ -26,8 +28,6 @@ import ghidra.util.xml.SpecXmlUtils;
|
||||||
import ghidra.xml.XmlElement;
|
import ghidra.xml.XmlElement;
|
||||||
import ghidra.xml.XmlPullParser;
|
import ghidra.xml.XmlPullParser;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
|
@ -152,6 +152,8 @@ public class SymbolTable {
|
||||||
sym = new StartSymbol();
|
sym = new StartSymbol();
|
||||||
else if (el.getName().equals("end_sym_head"))
|
else if (el.getName().equals("end_sym_head"))
|
||||||
sym = new EndSymbol();
|
sym = new EndSymbol();
|
||||||
|
else if (el.getName().equals("next2_sym_head"))
|
||||||
|
sym = new Next2Symbol();
|
||||||
else if (el.getName().equals("subtable_sym_head"))
|
else if (el.getName().equals("subtable_sym_head"))
|
||||||
sym = new SubtableSymbol();
|
sym = new SubtableSymbol();
|
||||||
else
|
else
|
||||||
|
|
|
@ -39,14 +39,15 @@ public class ConstTpl {
|
||||||
public static final int HANDLE = 1;
|
public static final int HANDLE = 1;
|
||||||
public static final int J_START = 2;
|
public static final int J_START = 2;
|
||||||
public static final int J_NEXT = 3;
|
public static final int J_NEXT = 3;
|
||||||
public static final int J_CURSPACE = 4;
|
public static final int J_NEXT2 = 4;
|
||||||
public static final int J_CURSPACE_SIZE = 5;
|
public static final int J_CURSPACE = 5;
|
||||||
public static final int SPACEID = 6;
|
public static final int J_CURSPACE_SIZE = 6;
|
||||||
public static final int J_RELATIVE = 7;
|
public static final int SPACEID = 7;
|
||||||
public static final int J_FLOWREF = 8;
|
public static final int J_RELATIVE = 8;
|
||||||
public static final int J_FLOWREF_SIZE = 9;
|
public static final int J_FLOWREF = 9;
|
||||||
public static final int J_FLOWDEST = 10;
|
public static final int J_FLOWREF_SIZE = 10;
|
||||||
public static final int J_FLOWDEST_SIZE = 11;
|
public static final int J_FLOWDEST = 11;
|
||||||
|
public static final int J_FLOWDEST_SIZE = 12;
|
||||||
|
|
||||||
public static final int V_SPACE = 0;
|
public static final int V_SPACE = 0;
|
||||||
public static final int V_OFFSET = 1;
|
public static final int V_OFFSET = 1;
|
||||||
|
@ -143,6 +144,8 @@ public class ConstTpl {
|
||||||
return walker.getAddr().getOffset();
|
return walker.getAddr().getOffset();
|
||||||
case J_NEXT:
|
case J_NEXT:
|
||||||
return walker.getNaddr().getOffset();
|
return walker.getNaddr().getOffset();
|
||||||
|
case J_NEXT2:
|
||||||
|
return walker.getN2addr().getOffset();
|
||||||
case J_FLOWREF:
|
case J_FLOWREF:
|
||||||
return walker.getFlowRefAddr().getOffset();
|
return walker.getFlowRefAddr().getOffset();
|
||||||
case J_FLOWREF_SIZE:
|
case J_FLOWREF_SIZE:
|
||||||
|
@ -315,6 +318,9 @@ public class ConstTpl {
|
||||||
else if (typestr.equals("next")) {
|
else if (typestr.equals("next")) {
|
||||||
type = J_NEXT;
|
type = J_NEXT;
|
||||||
}
|
}
|
||||||
|
else if (typestr.equals("next2")) {
|
||||||
|
type = J_NEXT2;
|
||||||
|
}
|
||||||
else if (typestr.equals("curspace")) {
|
else if (typestr.equals("curspace")) {
|
||||||
type = J_CURSPACE;
|
type = J_CURSPACE;
|
||||||
}
|
}
|
||||||
|
@ -379,6 +385,8 @@ public class ConstTpl {
|
||||||
return "[flowref_size]";
|
return "[flowref_size]";
|
||||||
case J_NEXT:
|
case J_NEXT:
|
||||||
return "[next]";
|
return "[next]";
|
||||||
|
case J_NEXT2:
|
||||||
|
return "[next2]";
|
||||||
case J_START:
|
case J_START:
|
||||||
return "[start]";
|
return "[start]";
|
||||||
case J_RELATIVE:
|
case J_RELATIVE:
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -289,6 +289,8 @@ public class SleighCompile extends SleighBase {
|
||||||
symtab.addSymbol(startsym);
|
symtab.addSymbol(startsym);
|
||||||
EndSymbol endsym = new EndSymbol(location, "inst_next", getConstantSpace());
|
EndSymbol endsym = new EndSymbol(location, "inst_next", getConstantSpace());
|
||||||
symtab.addSymbol(endsym);
|
symtab.addSymbol(endsym);
|
||||||
|
Next2Symbol next2sym = new Next2Symbol(location, "inst_next2", getConstantSpace());
|
||||||
|
symtab.addSymbol(next2sym);
|
||||||
EpsilonSymbol epsilon = new EpsilonSymbol(location, "epsilon", getConstantSpace());
|
EpsilonSymbol epsilon = new EpsilonSymbol(location, "epsilon", getConstantSpace());
|
||||||
symtab.addSymbol(epsilon);
|
symtab.addSymbol(epsilon);
|
||||||
}
|
}
|
||||||
|
@ -1280,7 +1282,8 @@ public class SleighCompile extends SleighBase {
|
||||||
VectorSTL<PatternValue> vallist = new VectorSTL<>();
|
VectorSTL<PatternValue> vallist = new VectorSTL<>();
|
||||||
pe.listValues(vallist);
|
pe.listValues(vallist);
|
||||||
for (int i = 0; i < vallist.size(); ++i) {
|
for (int i = 0; i < vallist.size(); ++i) {
|
||||||
if (vallist.get(i) instanceof EndInstructionValue) {
|
PatternValue v = vallist.get(i);
|
||||||
|
if (v instanceof EndInstructionValue || v instanceof Next2InstructionValue) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
||||||
|
@ -32,6 +31,7 @@ class Yylval {
|
||||||
OperandSymbol operandsym;
|
OperandSymbol operandsym;
|
||||||
StartSymbol startsym;
|
StartSymbol startsym;
|
||||||
EndSymbol endsym;
|
EndSymbol endsym;
|
||||||
|
Next2Symbol next2sym;
|
||||||
SubtableSymbol subtablesym;
|
SubtableSymbol subtablesym;
|
||||||
MacroSymbol macrosym;
|
MacroSymbol macrosym;
|
||||||
LabelSymbol labelsym;
|
LabelSymbol labelsym;
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
/* ###
|
||||||
|
* 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.slghpatexpress;
|
||||||
|
|
||||||
|
import java.io.PrintStream;
|
||||||
|
|
||||||
|
import org.jdom.Element;
|
||||||
|
|
||||||
|
import generic.stl.VectorSTL;
|
||||||
|
import ghidra.pcodeCPort.translate.Translate;
|
||||||
|
import ghidra.sleigh.grammar.Location;
|
||||||
|
|
||||||
|
public class Next2InstructionValue extends PatternValue {
|
||||||
|
|
||||||
|
public Next2InstructionValue(Location location) {
|
||||||
|
super(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TokenPattern genMinPattern(VectorSTL<TokenPattern> ops) {
|
||||||
|
return new TokenPattern(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TokenPattern genPattern(long val) {
|
||||||
|
return new TokenPattern(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long minValue() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long maxValue() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void saveXml(PrintStream s) {
|
||||||
|
s.append("<next2_exp/>");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void restoreXml(Element el, Translate trans) {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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.
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -0,0 +1,93 @@
|
||||||
|
/* ###
|
||||||
|
* 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.slghsymbol;
|
||||||
|
|
||||||
|
import java.io.PrintStream;
|
||||||
|
|
||||||
|
import org.jdom.Element;
|
||||||
|
|
||||||
|
import ghidra.pcodeCPort.semantics.ConstTpl;
|
||||||
|
import ghidra.pcodeCPort.semantics.VarnodeTpl;
|
||||||
|
import ghidra.pcodeCPort.sleighbase.SleighBase;
|
||||||
|
import ghidra.pcodeCPort.slghpatexpress.Next2InstructionValue;
|
||||||
|
import ghidra.pcodeCPort.slghpatexpress.PatternExpression;
|
||||||
|
import ghidra.pcodeCPort.space.AddrSpace;
|
||||||
|
import ghidra.sleigh.grammar.Location;
|
||||||
|
|
||||||
|
public class Next2Symbol extends SpecificSymbol {
|
||||||
|
private AddrSpace const_space;
|
||||||
|
private PatternExpression patexp;
|
||||||
|
|
||||||
|
public Next2Symbol(Location location) {
|
||||||
|
super(location);
|
||||||
|
patexp = null;
|
||||||
|
} // For use with restoreXml
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PatternExpression getPatternExpression() {
|
||||||
|
return patexp;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public symbol_type getType() {
|
||||||
|
return symbol_type.next2_symbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Next2Symbol(Location location, String nm, AddrSpace cspc) {
|
||||||
|
super(location, nm);
|
||||||
|
const_space = cspc;
|
||||||
|
patexp = new Next2InstructionValue(location);
|
||||||
|
patexp.layClaim();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void dispose() {
|
||||||
|
if (patexp != null) {
|
||||||
|
PatternExpression.release(patexp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return next instruction offset as a constant
|
||||||
|
@Override
|
||||||
|
public VarnodeTpl getVarnode() {
|
||||||
|
ConstTpl spc = new ConstTpl(const_space);
|
||||||
|
ConstTpl off = new ConstTpl(ConstTpl.const_type.j_next2);
|
||||||
|
ConstTpl sz_zero = new ConstTpl();
|
||||||
|
return new VarnodeTpl(location, spc, off, sz_zero);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void saveXml(PrintStream s) {
|
||||||
|
s.append("<next2_sym");
|
||||||
|
saveSleighSymbolXmlHeader(s);
|
||||||
|
s.println("/>");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void saveXmlHeader(PrintStream s) {
|
||||||
|
s.append("<next2_sym_head");
|
||||||
|
saveSleighSymbolXmlHeader(s);
|
||||||
|
s.println("/>");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void restoreXml(Element el, SleighBase trans) {
|
||||||
|
const_space = trans.getConstantSpace();
|
||||||
|
patexp = new Next2InstructionValue(null);
|
||||||
|
patexp.layClaim();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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.
|
||||||
|
|
|
@ -15,6 +15,12 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.pcodeCPort.slghsymbol;
|
package ghidra.pcodeCPort.slghsymbol;
|
||||||
|
|
||||||
|
import java.io.PrintStream;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.jdom.Element;
|
||||||
|
|
||||||
import generic.stl.IteratorSTL;
|
import generic.stl.IteratorSTL;
|
||||||
import generic.stl.VectorSTL;
|
import generic.stl.VectorSTL;
|
||||||
import ghidra.pcodeCPort.context.SleighError;
|
import ghidra.pcodeCPort.context.SleighError;
|
||||||
|
@ -22,12 +28,6 @@ import ghidra.pcodeCPort.sleighbase.SleighBase;
|
||||||
import ghidra.pcodeCPort.utils.XmlUtils;
|
import ghidra.pcodeCPort.utils.XmlUtils;
|
||||||
import ghidra.sleigh.grammar.Location;
|
import ghidra.sleigh.grammar.Location;
|
||||||
|
|
||||||
import java.io.PrintStream;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.jdom.Element;
|
|
||||||
|
|
||||||
public class SymbolTable {
|
public class SymbolTable {
|
||||||
|
|
||||||
private VectorSTL<SleighSymbol> symbollist = new VectorSTL<SleighSymbol>();
|
private VectorSTL<SleighSymbol> symbollist = new VectorSTL<SleighSymbol>();
|
||||||
|
@ -300,6 +300,9 @@ public class SymbolTable {
|
||||||
else if (el.getName().equals("end_sym_head")) {
|
else if (el.getName().equals("end_sym_head")) {
|
||||||
sym = new EndSymbol(location);
|
sym = new EndSymbol(location);
|
||||||
}
|
}
|
||||||
|
else if (el.getName().equals("next2_sym_head")) {
|
||||||
|
sym = new Next2Symbol(location);
|
||||||
|
}
|
||||||
else if (el.getName().equals("subtable_sym_head")) {
|
else if (el.getName().equals("subtable_sym_head")) {
|
||||||
sym = new SubtableSymbol(location);
|
sym = new SubtableSymbol(location);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -27,6 +27,7 @@ public enum symbol_type {
|
||||||
operand_symbol,
|
operand_symbol,
|
||||||
start_symbol, // inst_start, inst_ref, inst_def
|
start_symbol, // inst_start, inst_ref, inst_def
|
||||||
end_symbol, // inst_next
|
end_symbol, // inst_next
|
||||||
|
next2_symbol, // inst_next2
|
||||||
subtable_symbol,
|
subtable_symbol,
|
||||||
macro_symbol,
|
macro_symbol,
|
||||||
section_symbol,
|
section_symbol,
|
||||||
|
|
|
@ -63,6 +63,7 @@ public interface InstructionContext {
|
||||||
* at the specified address. The returned ParserContext may be cast to the prototype's
|
* at the specified address. The returned ParserContext may be cast to the prototype's
|
||||||
* implementation without checking. This method will throw an UnknownContextException
|
* implementation without checking. This method will throw an UnknownContextException
|
||||||
* if a compatible ParserContext is not found at the specified address.
|
* if a compatible ParserContext is not found at the specified address.
|
||||||
|
* @param instructionAddress instruction address of requested context
|
||||||
* @return the instruction parser context at the specified instruction address
|
* @return the instruction parser context at the specified instruction address
|
||||||
* @throws UnknownContextException if the instruction at the specified address
|
* @throws UnknownContextException if the instruction at the specified address
|
||||||
* was not previously parsed or attempting to instantiate context resulted in an
|
* was not previously parsed or attempting to instantiate context resulted in an
|
||||||
|
|
|
@ -85,6 +85,7 @@ public class PcodeParser extends PcodeCompile {
|
||||||
Location internalLoc = Location.INTERNALLY_DEFINED;
|
Location internalLoc = Location.INTERNALLY_DEFINED;
|
||||||
symbolMap.put("inst_start", new StartSymbol(internalLoc, "inst_start", getConstantSpace()));
|
symbolMap.put("inst_start", new StartSymbol(internalLoc, "inst_start", getConstantSpace()));
|
||||||
symbolMap.put("inst_next", new EndSymbol(internalLoc, "inst_next", getConstantSpace()));
|
symbolMap.put("inst_next", new EndSymbol(internalLoc, "inst_next", getConstantSpace()));
|
||||||
|
symbolMap.put("inst_next2", new Next2Symbol(internalLoc, "inst_next2", getConstantSpace()));
|
||||||
symbolMap.put("inst_ref", new FlowRefSymbol(internalLoc, "inst_ref", getConstantSpace()));
|
symbolMap.put("inst_ref", new FlowRefSymbol(internalLoc, "inst_ref", getConstantSpace()));
|
||||||
symbolMap.put("inst_dest",
|
symbolMap.put("inst_dest",
|
||||||
new FlowDestSymbol(internalLoc, "inst_dest", getConstantSpace()));
|
new FlowDestSymbol(internalLoc, "inst_dest", getConstantSpace()));
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
#### immediates
|
#### load immediate 0000 000x xxxx xxxx
|
||||||
# 0iii dddd iiii iiii # imm rd, i load 11-bit unsigned int into rd
|
# 00ii dddd iiii iiii # imm rd, i load 10-bit unsigned int into rd
|
||||||
# 10nn dddd nnnn nnnn # simm rd, n load 10-bit signed int into rd
|
# 01nn dddd nnnn nnnn # simm rd, n load 10-bit signed int into rd
|
||||||
#
|
#
|
||||||
#### arithmetic
|
#### misc 100x xxxx xxxx xxxx
|
||||||
|
# 1000 0000 0000 0ccc # skcc if ccc goto inst_next2 (conditional skip instruction)
|
||||||
|
#
|
||||||
|
#### arithmetic 1100 xxxx
|
||||||
# 1100 0000 ssss tttt # add rs, rt rs = rs + rt
|
# 1100 0000 ssss tttt # add rs, rt rs = rs + rt
|
||||||
# 1100 0001 ssss tttt # sub rs, rt rs = rs - rt
|
# 1100 0001 ssss tttt # sub rs, rt rs = rs - rt
|
||||||
# 1100 0010 ssss tttt # rsub rs, rt rs = rt - rs
|
# 1100 0010 ssss tttt # rsub rs, rt rs = rt - rs
|
||||||
|
@ -40,7 +43,7 @@
|
||||||
# 1101 0110 ssss tttt # load rs, [rt] rs = [rt]
|
# 1101 0110 ssss tttt # load rs, [rt] rs = [rt]
|
||||||
# 1101 0111 ssss tttt # store [rs], rt [rs] = rt
|
# 1101 0111 ssss tttt # store [rs], rt [rs] = rt
|
||||||
# 1101 1111 ssss tttt # mov rs, rt rs = rt
|
# 1101 1111 ssss tttt # mov rs, rt rs = rt
|
||||||
#
|
|
||||||
#### flow
|
#### flow
|
||||||
# 1110 nnnn nnnn 0ccc # brcc n if ccc goto pc + n
|
# 1110 nnnn nnnn 0ccc # brcc n if ccc goto pc + n
|
||||||
# 1110 nnnn nnnn 1ccc # brdscc n if ccc goto pc + n with delay slot
|
# 1110 nnnn nnnn 1ccc # brdscc n if ccc goto pc + n with delay slot
|
||||||
|
@ -54,7 +57,7 @@
|
||||||
# 1111 0110 ssss 1ccc # call rs if ccc call rs
|
# 1111 0110 ssss 1ccc # call rs if ccc call rs
|
||||||
# 1111 1nnn nnnn nnnn # call n call n
|
# 1111 1nnn nnnn nnnn # call n call n
|
||||||
#
|
#
|
||||||
#### user-defined
|
#### user-defined 1010 xxxx
|
||||||
# 1010 0010 ssss 0000 # user_one rs user_one rs
|
# 1010 0010 ssss 0000 # user_one rs user_one rs
|
||||||
# 1010 0010 ssss 0000 # user_two rs user_two rs
|
# 1010 0010 ssss 0000 # user_two rs user_two rs
|
||||||
# 1010 0011 0000 0000 # user_three user_three
|
# 1010 0011 0000 0000 # user_three user_three
|
||||||
|
@ -63,11 +66,11 @@
|
||||||
# 1010 0110 ssss 0000 # user_six rs user_six rs
|
# 1010 0110 ssss 0000 # user_six rs user_six rs
|
||||||
# 1010 1000 0000 0000 # unimpl
|
# 1010 1000 0000 0000 # unimpl
|
||||||
#
|
#
|
||||||
#### RESERVED
|
#### RESERVED / UNUSED
|
||||||
# 1101 1001 xxxx xxxx # RESERVED BANK
|
# 1011 xxxx xxxx xxxx # UNUSED
|
||||||
# 1101 1010 xxxx xxxx # RESERVED BANK
|
# 1101 1001 xxxx xxxx # RESERVED BANK (consumed by toy_builder.sinc)
|
||||||
# 1111 0111 xxxx xxxx # RESERVED BANK
|
# 1101 1010 xxxx xxxx # RESERVED BANK (consumed by toy_builder.sinc)
|
||||||
|
# 1111 0111 xxxx xxxx # RESERVED BANK (consumed by toy_builder.sinc)
|
||||||
|
|
||||||
define token instr(16)
|
define token instr(16)
|
||||||
op1515 = (15, 15)
|
op1515 = (15, 15)
|
||||||
|
@ -75,13 +78,14 @@ define token instr(16)
|
||||||
op1215 = (12, 15)
|
op1215 = (12, 15)
|
||||||
op1111 = (11, 11)
|
op1111 = (11, 11)
|
||||||
op0811 = (8, 11)
|
op0811 = (8, 11)
|
||||||
|
op0407 = (4, 7)
|
||||||
op0007 = (0, 7)
|
op0007 = (0, 7)
|
||||||
op0003 = (0, 3)
|
op0003 = (0, 3)
|
||||||
op0303 = (3, 3)
|
op0303 = (3, 3)
|
||||||
rd = (8, 11)
|
rd = (8, 11)
|
||||||
rs = (4, 7)
|
rs = (4, 7)
|
||||||
rt = (0, 3)
|
rt = (0, 3)
|
||||||
imm1214 = (12, 14)
|
imm1213 = (12, 13)
|
||||||
imm0007 = (0, 7)
|
imm0007 = (0, 7)
|
||||||
imm0003 = (0, 3)
|
imm0003 = (0, 3)
|
||||||
simm1213 = (12, 13) signed
|
simm1213 = (12, 13) signed
|
||||||
|
@ -104,7 +108,7 @@ Simm4: "#"^simm0003 is simm0003 { export *[const]:$(SIZE) simm0003; }
|
||||||
Simm10: "#"^computed is simm1213 & imm0007 [ computed = (simm1213 << 8) | imm0007; ] { export *[const]:$(SIZE) computed; }
|
Simm10: "#"^computed is simm1213 & imm0007 [ computed = (simm1213 << 8) | imm0007; ] { export *[const]:$(SIZE) computed; }
|
||||||
|
|
||||||
Imm4: "#"^imm0003 is imm0003 { export *[const]:$(SIZE) imm0003; }
|
Imm4: "#"^imm0003 is imm0003 { export *[const]:$(SIZE) imm0003; }
|
||||||
Imm11: "#"^computed is imm1214 & imm0007 [ computed = (imm1214 << 8) | imm0007; ] { export *[const]:$(SIZE) computed; }
|
Imm10: "#"^computed is imm1213 & imm0007 [ computed = (imm1213 << 8) | imm0007; ] { export *[const]:$(SIZE) computed; }
|
||||||
|
|
||||||
Rel8: addr is simm0007 [ addr = inst_start + simm0007; ] { export *:$(SIZE) addr; }
|
Rel8: addr is simm0007 [ addr = inst_start + simm0007; ] { export *:$(SIZE) addr; }
|
||||||
Rel82: addr is simm0411 [ addr = inst_start + simm0411; ] { export *:$(SIZE) addr; }
|
Rel82: addr is simm0411 [ addr = inst_start + simm0411; ] { export *:$(SIZE) addr; }
|
||||||
|
@ -148,7 +152,7 @@ define pcodeop pcodeop_three;
|
||||||
|
|
||||||
# operations
|
# operations
|
||||||
|
|
||||||
:imm rd, Imm11 is $(INSTR_PHASE) op1515=0x0 & rd & Imm11 { logicflags(); rd = Imm11; resultflags(rd); }
|
:imm rd, Imm10 is $(INSTR_PHASE) op1515=0x0 & rd & Imm10 { logicflags(); rd = Imm10; resultflags(rd); }
|
||||||
:simm rd, Simm10 is $(INSTR_PHASE) op1415=0x2 & rd & Simm10 { logicflags(); rd = Simm10; resultflags(rd); }
|
:simm rd, Simm10 is $(INSTR_PHASE) op1415=0x2 & rd & Simm10 { logicflags(); rd = Simm10; resultflags(rd); }
|
||||||
|
|
||||||
:add rs, rt is $(INSTR_PHASE) op1215=0xc & op0811=0x0 & rs & rt { addflags(rs, rt); rs = rs + rt; resultflags(rs); }
|
:add rs, rt is $(INSTR_PHASE) op1215=0xc & op0811=0x0 & rs & rt { addflags(rs, rt); rs = rs + rt; resultflags(rs); }
|
||||||
|
@ -197,6 +201,8 @@ define pcodeop pcodeop_three;
|
||||||
:store RS, rt is $(INSTR_PHASE) op1215=0xd & op0811=0x7 & RS & rt { RS = rt; logicflags(); resultflags(rt); }
|
:store RS, rt is $(INSTR_PHASE) op1215=0xd & op0811=0x7 & RS & rt { RS = rt; logicflags(); resultflags(rt); }
|
||||||
:mov rs, rt is $(INSTR_PHASE) op1215=0xd & op0811=0xf & rs & rt { rs = rt; logicflags(); resultflags(rs); }
|
:mov rs, rt is $(INSTR_PHASE) op1215=0xd & op0811=0xf & rs & rt { rs = rt; logicflags(); resultflags(rs); }
|
||||||
|
|
||||||
|
:sk^CC is $(INSTR_PHASE) op1215=0x8 & op0811=0x0 & op0407=0x0 & op0303=0x0 & CC & Rel82 { if (CC) goto inst_next2; }
|
||||||
|
|
||||||
:br^COND Rel82 is $(INSTR_PHASE) op1215=0xe & op0303=0x0 & COND & Rel82 { build COND; goto Rel82; }
|
:br^COND Rel82 is $(INSTR_PHASE) op1215=0xe & op0303=0x0 & COND & Rel82 { build COND; goto Rel82; }
|
||||||
:brds^COND Rel82 is $(INSTR_PHASE) op1215=0xe & op0303=0x1 & COND & Rel82 { build COND; delayslot(1); goto Rel82; }
|
:brds^COND Rel82 is $(INSTR_PHASE) op1215=0xe & op0303=0x1 & COND & Rel82 { build COND; delayslot(1); goto Rel82; }
|
||||||
:br^COND rs is $(INSTR_PHASE) op1215=0xf & op0811=0x0 & COND & rs & op0303=0x0 { build COND; goto [rs]; }
|
:br^COND rs is $(INSTR_PHASE) op1215=0xf & op0811=0x0 & COND & rs & op0303=0x0 { build COND; goto [rs]; }
|
||||||
|
|
|
@ -1502,6 +1502,35 @@ public class DisassemblerTest extends AbstractGhidraHeadlessIntegrationTest {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 10: skeq
|
||||||
|
* 12: bral 20 --------+
|
||||||
|
* 14: ret |
|
||||||
|
* |
|
||||||
|
* 20: mov r0, #123 <-+
|
||||||
|
* 22: ret
|
||||||
|
*
|
||||||
|
* Test skip instruction
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testDisassemblerSkip() throws Exception {
|
||||||
|
|
||||||
|
programBuilder.addBytesSkipConditional(10);
|
||||||
|
programBuilder.addBytesBranch(12, 20);
|
||||||
|
programBuilder.addBytesReturn(14);
|
||||||
|
|
||||||
|
programBuilder.addBytesMoveImmediate(20, (short) 123);
|
||||||
|
programBuilder.addBytesReturn(22);
|
||||||
|
|
||||||
|
AddressSetView disAddrs = disassembler.disassemble(addr(10), null);
|
||||||
|
assertEquals(addrset(range(10, 15), range(20, 23)), disAddrs);
|
||||||
|
|
||||||
|
verifyInstructionPresence();
|
||||||
|
|
||||||
|
verifyNoBookmarks();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 10: bral 200 (error on flow to non-existing memory)
|
* 10: bral 200 (error on flow to non-existing memory)
|
||||||
*
|
*
|
||||||
|
|
|
@ -71,6 +71,26 @@ public class PcodeParserTest extends AbstractGhidraHeadlessIntegrationTest {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean testInstNext2Constant(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_NEXT2) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (vn.getSize().getType() != ConstTpl.REAL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (vn.getSize().getReal() != size) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean testInstNext(VarnodeTpl vn) {
|
public boolean testInstNext(VarnodeTpl vn) {
|
||||||
assertNotNull(vn);
|
assertNotNull(vn);
|
||||||
if (vn.getSpace().getType() != ConstTpl.J_CURSPACE) {
|
if (vn.getSpace().getType() != ConstTpl.J_CURSPACE) {
|
||||||
|
@ -85,6 +105,20 @@ public class PcodeParserTest extends AbstractGhidraHeadlessIntegrationTest {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean testInstNext2(VarnodeTpl vn) {
|
||||||
|
assertNotNull(vn);
|
||||||
|
if (vn.getSpace().getType() != ConstTpl.J_CURSPACE) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (vn.getOffset().getType() != ConstTpl.J_NEXT2) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (vn.getSize().getType() != ConstTpl.J_CURSPACE_SIZE) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean testRelative(VarnodeTpl vn, int labelid, int size) {
|
public boolean testRelative(VarnodeTpl vn, int labelid, int size) {
|
||||||
assertNotNull(vn);
|
assertNotNull(vn);
|
||||||
if (vn.getSpace().getType() != ConstTpl.SPACEID) {
|
if (vn.getSpace().getType() != ConstTpl.SPACEID) {
|
||||||
|
@ -175,6 +209,7 @@ public class PcodeParserTest extends AbstractGhidraHeadlessIntegrationTest {
|
||||||
long uniqueBase = UniqueLayout.INJECT.getOffset(lang);
|
long uniqueBase = UniqueLayout.INJECT.getOffset(lang);
|
||||||
|
|
||||||
String pcodeStatements = "tmp:1 = inst_next;\n" + "if (AX == 0) goto inst_next;\n" +
|
String pcodeStatements = "tmp:1 = inst_next;\n" + "if (AX == 0) goto inst_next;\n" +
|
||||||
|
"tmp2:1 = inst_next2;\n" + "if (BX == 0) goto inst_next2;\n" +
|
||||||
"call [ECX];\n" + "if (BX != 1) goto <lab>;\n" + "CX = 0;\n" + "<lab>\n" +
|
"call [ECX];\n" + "if (BX != 1) goto <lab>;\n" + "CX = 0;\n" + "<lab>\n" +
|
||||||
"BX = CX << 2;\n" + "in1 = in2 + 7;";
|
"BX = CX << 2;\n" + "in1 = in2 + 7;";
|
||||||
|
|
||||||
|
@ -186,8 +221,9 @@ public class PcodeParserTest extends AbstractGhidraHeadlessIntegrationTest {
|
||||||
assertNull(template.getResult());
|
assertNull(template.getResult());
|
||||||
assertEquals(template.getNumLabels(), 1);
|
assertEquals(template.getNumLabels(), 1);
|
||||||
OpTpl[] vec = template.getOpVec();
|
OpTpl[] vec = template.getOpVec();
|
||||||
assertEquals(vec.length, 10);
|
assertEquals(vec.length, 13);
|
||||||
|
|
||||||
|
// inst_next
|
||||||
assertEquals(vec[0].getOpcode(), PcodeOp.COPY);
|
assertEquals(vec[0].getOpcode(), PcodeOp.COPY);
|
||||||
assertTrue(testVarnode(vec[0].getOutput(), SpaceNames.UNIQUE_SPACE_NAME, uniqueBase, 1));
|
assertTrue(testVarnode(vec[0].getOutput(), SpaceNames.UNIQUE_SPACE_NAME, uniqueBase, 1));
|
||||||
assertEquals(vec[0].getInput().length, 1);
|
assertEquals(vec[0].getInput().length, 1);
|
||||||
|
@ -207,46 +243,68 @@ public class PcodeParserTest extends AbstractGhidraHeadlessIntegrationTest {
|
||||||
assertTrue(
|
assertTrue(
|
||||||
testVarnode(vec[2].getInput()[1], SpaceNames.UNIQUE_SPACE_NAME, uniqueBase + 0x80, 1));
|
testVarnode(vec[2].getInput()[1], SpaceNames.UNIQUE_SPACE_NAME, uniqueBase + 0x80, 1));
|
||||||
|
|
||||||
assertEquals(vec[3].getOpcode(), PcodeOp.CALLIND);
|
// inst_next2
|
||||||
assertNull(vec[3].getOutput());
|
assertEquals(vec[3].getOpcode(), PcodeOp.COPY);
|
||||||
assertEquals(vec[3].getInput().length, 1);
|
|
||||||
assertTrue(testVarnode(vec[3].getInput()[0], "register", 4, 4));
|
|
||||||
|
|
||||||
assertEquals(vec[4].getOpcode(), PcodeOp.INT_NOTEQUAL);
|
|
||||||
assertTrue(
|
assertTrue(
|
||||||
testVarnode(vec[4].getOutput(), SpaceNames.UNIQUE_SPACE_NAME, uniqueBase + 0x100, 1));
|
testVarnode(vec[3].getOutput(), SpaceNames.UNIQUE_SPACE_NAME, uniqueBase + 0x100, 1));
|
||||||
|
assertEquals(vec[3].getInput().length, 1);
|
||||||
|
assertTrue(testInstNext2Constant(vec[3].getInput()[0], 1));
|
||||||
|
|
||||||
|
assertEquals(vec[4].getOpcode(), PcodeOp.INT_EQUAL);
|
||||||
|
assertTrue(
|
||||||
|
testVarnode(vec[4].getOutput(), SpaceNames.UNIQUE_SPACE_NAME, uniqueBase + 0x180, 1));
|
||||||
assertEquals(vec[4].getInput().length, 2);
|
assertEquals(vec[4].getInput().length, 2);
|
||||||
assertTrue(testVarnode(vec[4].getInput()[0], "register", 0xc, 2));
|
assertTrue(testVarnode(vec[4].getInput()[0], "register", 0xc, 2));
|
||||||
assertTrue(testVarnode(vec[4].getInput()[1], SpaceNames.CONSTANT_SPACE_NAME, 1, 2));
|
assertTrue(testVarnode(vec[4].getInput()[1], SpaceNames.CONSTANT_SPACE_NAME, 0, 2));
|
||||||
|
|
||||||
assertEquals(vec[5].getOpcode(), PcodeOp.CBRANCH);
|
assertEquals(vec[5].getOpcode(), PcodeOp.CBRANCH);
|
||||||
assertNull(vec[5].getOutput());
|
assertNull(vec[5].getOutput());
|
||||||
assertEquals(vec[5].getInput().length, 2);
|
assertEquals(vec[5].getInput().length, 2);
|
||||||
assertTrue(testRelative(vec[5].getInput()[0], 0, 4));
|
assertTrue(testInstNext2(vec[5].getInput()[0]));
|
||||||
assertTrue(
|
assertTrue(
|
||||||
testVarnode(vec[5].getInput()[1], SpaceNames.UNIQUE_SPACE_NAME, uniqueBase + 0x100, 1));
|
testVarnode(vec[5].getInput()[1], SpaceNames.UNIQUE_SPACE_NAME, uniqueBase + 0x180, 1));
|
||||||
|
|
||||||
assertEquals(vec[6].getOpcode(), PcodeOp.COPY);
|
// call
|
||||||
assertTrue(testVarnode(vec[6].getOutput(), "register", 4, 2));
|
assertEquals(vec[6].getOpcode(), PcodeOp.CALLIND);
|
||||||
|
assertNull(vec[6].getOutput());
|
||||||
assertEquals(vec[6].getInput().length, 1);
|
assertEquals(vec[6].getInput().length, 1);
|
||||||
assertTrue(testVarnode(vec[6].getInput()[0], SpaceNames.CONSTANT_SPACE_NAME, 0, 2));
|
assertTrue(testVarnode(vec[6].getInput()[0], "register", 4, 4));
|
||||||
|
|
||||||
assertEquals(vec[7].getOpcode(), PcodeOp.PTRADD); // label
|
assertEquals(vec[7].getOpcode(), PcodeOp.INT_NOTEQUAL);
|
||||||
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(
|
assertTrue(
|
||||||
testVarnodeHandleSize(vec[9].getInput()[1], SpaceNames.CONSTANT_SPACE_NAME, 7, 0));
|
testVarnode(vec[7].getOutput(), SpaceNames.UNIQUE_SPACE_NAME, uniqueBase + 0x200, 1));
|
||||||
|
assertEquals(vec[7].getInput().length, 2);
|
||||||
|
assertTrue(testVarnode(vec[7].getInput()[0], "register", 0xc, 2));
|
||||||
|
assertTrue(testVarnode(vec[7].getInput()[1], SpaceNames.CONSTANT_SPACE_NAME, 1, 2));
|
||||||
|
|
||||||
|
assertEquals(vec[8].getOpcode(), PcodeOp.CBRANCH);
|
||||||
|
assertNull(vec[8].getOutput());
|
||||||
|
assertEquals(vec[8].getInput().length, 2);
|
||||||
|
assertTrue(testRelative(vec[8].getInput()[0], 0, 4));
|
||||||
|
assertTrue(
|
||||||
|
testVarnode(vec[8].getInput()[1], SpaceNames.UNIQUE_SPACE_NAME, uniqueBase + 0x200, 1));
|
||||||
|
|
||||||
|
assertEquals(vec[9].getOpcode(), PcodeOp.COPY);
|
||||||
|
assertTrue(testVarnode(vec[9].getOutput(), "register", 4, 2));
|
||||||
|
assertEquals(vec[9].getInput().length, 1);
|
||||||
|
assertTrue(testVarnode(vec[9].getInput()[0], SpaceNames.CONSTANT_SPACE_NAME, 0, 2));
|
||||||
|
|
||||||
|
assertEquals(vec[10].getOpcode(), PcodeOp.PTRADD); // label
|
||||||
|
assertNull(vec[10].getOutput());
|
||||||
|
assertEquals(vec[10].getInput().length, 1);
|
||||||
|
assertTrue(testVarnode(vec[10].getInput()[0], SpaceNames.CONSTANT_SPACE_NAME, 0, 4));
|
||||||
|
|
||||||
|
assertEquals(vec[11].getOpcode(), PcodeOp.INT_LEFT);
|
||||||
|
assertTrue(testVarnode(vec[11].getOutput(), "register", 0xc, 2));
|
||||||
|
assertEquals(vec[11].getInput().length, 2);
|
||||||
|
assertTrue(testVarnode(vec[11].getInput()[0], "register", 0x4, 2));
|
||||||
|
assertTrue(testVarnode(vec[11].getInput()[1], SpaceNames.CONSTANT_SPACE_NAME, 2, 4));
|
||||||
|
|
||||||
|
assertEquals(vec[12].getOpcode(), PcodeOp.INT_ADD);
|
||||||
|
assertTrue(testParameter(vec[12].getOutput(), 0));
|
||||||
|
assertEquals(vec[12].getInput().length, 2);
|
||||||
|
assertTrue(testParameter(vec[12].getInput()[0], 1));
|
||||||
|
assertTrue(
|
||||||
|
testVarnodeHandleSize(vec[12].getInput()[1], SpaceNames.CONSTANT_SPACE_NAME, 7, 0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue