GP-2480 Add sleigh compiler support for inst_next2

This commit is contained in:
ghidra1
2022-08-18 17:27:39 -04:00
parent 39baf3a691
commit 8d4a6c213e
84 changed files with 3623 additions and 2807 deletions
@@ -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>&lt;callfixup&gt;</code>, the <code>&lt;body&gt;</code> tag is fed straight to the SLEIGH semantic As with a <code>&lt;callfixup&gt;</code>, the <code>&lt;body&gt;</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>&lt;input&gt;</code> or <code>&lt;output&gt;</code> names, and it can also refer to via their <code>&lt;input&gt;</code> or <code>&lt;output&gt;</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.

Some files were not shown because too many files have changed in this diff Show More