mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-05-20 23:08:31 +08:00
GP-2480 Add sleigh compiler support for inst_next2
This commit is contained in:
+2
-2
@@ -105,14 +105,14 @@ public class DebuggerStateEditingPluginIntegrationTest extends AbstractGhidraHea
|
||||
assertTrue(
|
||||
helper.patchInstructionAction.isAddToPopup(listingProvider.getActionContext(null)));
|
||||
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());
|
||||
|
||||
long snap = traceManager.getCurrent().getViewSnap();
|
||||
assertTrue(DBTraceUtils.isScratch(snap));
|
||||
byte[] bytes = new byte[2];
|
||||
view.getMemory().getBytes(tb.addr(0x00400123), bytes);
|
||||
assertArrayEquals(tb.arr(0x40, 1234), bytes);
|
||||
assertArrayEquals(tb.arr(0x30, 0xd2), bytes);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+2
-2
@@ -86,8 +86,8 @@ public class DebuggerPcodeStepperProviderTest extends AbstractGhidraHeadedDebugg
|
||||
|
||||
Assembler asm = Assemblers.getAssembler(tb.trace.getFixedProgramView(0));
|
||||
iit = asm.assemble(start,
|
||||
"imm r0, #1234",
|
||||
"imm r1, #2045"); // 11 bits unsigned
|
||||
"imm r0, #0x3d2",
|
||||
"imm r1, #911"); // 10 bits unsigned
|
||||
|
||||
}
|
||||
imm1234 = iit.next();
|
||||
|
||||
+7
-7
@@ -309,7 +309,7 @@ public class TracePcodeEmulatorTest extends AbstractGhidraHeadlessIntegrationTes
|
||||
"pc = 0x00400000;",
|
||||
"sp = 0x00110000;"),
|
||||
List.of(
|
||||
"imm r0, #1234")); // decimal
|
||||
"imm r0, #911")); // decimal
|
||||
|
||||
TracePcodeEmulator emu = new TracePcodeEmulator(tb.trace, 0);
|
||||
PcodeThread<byte[]> emuThread = emu.newThread(thread.getPath());
|
||||
@@ -324,7 +324,7 @@ public class TracePcodeEmulatorTest extends AbstractGhidraHeadlessIntegrationTes
|
||||
TraceSleighUtils.evaluate("sp", tb.trace, 1, thread, 0));
|
||||
assertEquals(BigInteger.valueOf(0x00400002),
|
||||
TraceSleighUtils.evaluate("pc", tb.trace, 1, thread, 0));
|
||||
assertEquals(BigInteger.valueOf(1234),
|
||||
assertEquals(BigInteger.valueOf(911),
|
||||
TraceSleighUtils.evaluate("r0", tb.trace, 1, thread, 0));
|
||||
}
|
||||
}
|
||||
@@ -341,9 +341,9 @@ public class TracePcodeEmulatorTest extends AbstractGhidraHeadlessIntegrationTes
|
||||
"sp = 0x00110000;"),
|
||||
List.of(
|
||||
"brds 0x00400006",
|
||||
"imm r0, #1234", // decimal
|
||||
"imm r0, #2020",
|
||||
"imm r1, #2021"));
|
||||
"imm r0, #911", // decimal
|
||||
"imm r0, #860",
|
||||
"imm r1, #861"));
|
||||
|
||||
TracePcodeEmulator emu = new TracePcodeEmulator(tb.trace, 0);
|
||||
PcodeThread<byte[]> emuThread = emu.newThread(thread.getPath());
|
||||
@@ -357,9 +357,9 @@ public class TracePcodeEmulatorTest extends AbstractGhidraHeadlessIntegrationTes
|
||||
|
||||
assertEquals(BigInteger.valueOf(0x00400008),
|
||||
TraceSleighUtils.evaluate("pc", tb.trace, 1, thread, 0));
|
||||
assertEquals(BigInteger.valueOf(1234),
|
||||
assertEquals(BigInteger.valueOf(911),
|
||||
TraceSleighUtils.evaluate("r0", tb.trace, 1, thread, 0));
|
||||
assertEquals(BigInteger.valueOf(2021),
|
||||
assertEquals(BigInteger.valueOf(861),
|
||||
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) {
|
||||
appender.appendLabel("inst_next");
|
||||
}
|
||||
else if (offset.getType() == ConstTpl.J_NEXT2) {
|
||||
appender.appendLabel("inst_next2");
|
||||
}
|
||||
else {
|
||||
formatAddress(appender, null, offset, size);
|
||||
}
|
||||
|
||||
@@ -494,6 +494,27 @@ public class ToyProgramBuilder extends ProgramBuilder {
|
||||
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)
|
||||
* @param offset instruction address offset
|
||||
|
||||
+5
-5
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
package ghidra.app.plugin.core.assembler;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.*;
|
||||
|
||||
@@ -90,8 +90,8 @@ public class AssemblerPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
@Test
|
||||
public void testActionPatchInstructionNoExisting() throws Exception {
|
||||
Address address = space.getAddress(0x00400000);
|
||||
Instruction ins = helper.patchInstructionAt(address, "", "imm r0, #1234");
|
||||
assertEquals("imm r0,#0x4d2", ins.toString());
|
||||
Instruction ins = helper.patchInstructionAt(address, "", "imm r0, #911");
|
||||
assertEquals("imm r0,#0x38f", ins.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -99,11 +99,11 @@ public class AssemblerPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
Address address = space.getAddress(0x00400000);
|
||||
Assembler asm = Assemblers.getAssembler(program);
|
||||
try (ProgramTransaction trans = ProgramTransaction.open(program, "Assemble pre-existing")) {
|
||||
asm.assemble(address, "imm r0,#0x4d2");
|
||||
asm.assemble(address, "imm r0,#0x3d2");
|
||||
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());
|
||||
}
|
||||
|
||||
|
||||
@@ -106,6 +106,7 @@ public:
|
||||
void applyCommits(void);
|
||||
const Address &getAddr(void) const { return addr; }
|
||||
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 &getRefAddr(void) const { return calladdr; }
|
||||
AddrSpace *getCurSpace(void) const { return addr.getSpace(); }
|
||||
@@ -147,6 +148,7 @@ public:
|
||||
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 &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 &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(); }
|
||||
|
||||
@@ -791,7 +791,7 @@ void Funcdata::doLiveInject(InjectPayload *payload,const Address &addr,BlockBasi
|
||||
|
||||
emitter.setFuncdata(this);
|
||||
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;
|
||||
|
||||
list<PcodeOp *>::const_iterator deaditer = obank.endDead();
|
||||
|
||||
@@ -69,6 +69,7 @@ public:
|
||||
/// concrete Varnodes. This class contains the context dependent data to resolve:
|
||||
/// - inst_start -- the address where the injection occurs
|
||||
/// - 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_ref -- Target of reference on injected instruction
|
||||
/// - \<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;
|
||||
StartSymbol *startsym;
|
||||
EndSymbol *endsym;
|
||||
Next2Symbol *next2sym;
|
||||
OperandSymbol *operandsym;
|
||||
VarnodeSymbol *varsym;
|
||||
SpecificSymbol *specsym;
|
||||
@@ -76,6 +77,7 @@
|
||||
%token <operandsym> OPERANDSYM
|
||||
%token <startsym> STARTSYM
|
||||
%token <endsym> ENDSYM
|
||||
%token <next2sym> NEXT2SYM
|
||||
%token <labelsym> LABELSYM
|
||||
|
||||
%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; }
|
||||
| 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; }
|
||||
| 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; }
|
||||
@@ -221,6 +224,7 @@ specificsymbol: VARSYM { $$ = $1; }
|
||||
| OPERANDSYM { $$ = $1; }
|
||||
| STARTSYM { $$ = $1; }
|
||||
| ENDSYM { $$ = $1; }
|
||||
| NEXT2SYM { $$ = $1; }
|
||||
;
|
||||
paramlist: /* EMPTY */ { $$ = new vector<ExprTree *>; }
|
||||
| expr { $$ = new vector<ExprTree *>; $$->push_back($1); }
|
||||
@@ -749,6 +753,9 @@ int4 PcodeSnippet::lex(void)
|
||||
case SleighSymbol::end_symbol:
|
||||
yylval.endsym = (EndSymbol *)sym;
|
||||
return ENDSYM;
|
||||
case SleighSymbol::next2_symbol:
|
||||
yylval.next2sym = (Next2Symbol *)sym;
|
||||
return NEXT2SYM;
|
||||
case SleighSymbol::label_symbol:
|
||||
yylval.labelsym = (LabelSymbol *)sym;
|
||||
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
|
||||
case j_next:
|
||||
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:
|
||||
return walker.getRefAddr().getOffset();
|
||||
case j_flowref_size:
|
||||
@@ -349,6 +351,9 @@ void ConstTpl::saveXml(ostream &s) const
|
||||
case j_next:
|
||||
s << "next\"/>";
|
||||
break;
|
||||
case j_next2:
|
||||
s << "next2\"/>";
|
||||
break;
|
||||
case j_curspace:
|
||||
s << "curspace\"/>";
|
||||
break;
|
||||
@@ -404,6 +409,9 @@ void ConstTpl::restoreXml(const Element *el,const AddrSpaceManager *manage)
|
||||
else if (typestring=="next") {
|
||||
type = j_next;
|
||||
}
|
||||
else if (typestring=="next2") {
|
||||
type = j_next2;
|
||||
}
|
||||
else if (typestring=="curspace") {
|
||||
type = j_curspace;
|
||||
}
|
||||
|
||||
@@ -30,9 +30,9 @@ class Translate; // Forward declaration
|
||||
class HandleTpl; // Forward declaration
|
||||
class ConstTpl {
|
||||
public:
|
||||
enum const_type { real=0, handle=1, j_start=2, j_next=3, j_curspace=4,
|
||||
j_curspace_size=5, spaceid=6, j_relative=7,
|
||||
j_flowref=8, j_flowref_size=9, j_flowdest=10, j_flowdest_size=11 };
|
||||
enum const_type { real=0, handle=1, j_start=2, j_next=3, j_next2=4, j_curspace=5,
|
||||
j_curspace_size=6, spaceid=7, j_relative=8,
|
||||
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 };
|
||||
private:
|
||||
const_type type;
|
||||
|
||||
@@ -1789,7 +1789,7 @@ SleighCompile::SleighCompile(void)
|
||||
}
|
||||
|
||||
/// 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
|
||||
void SleighCompile::predefinedSymbols(void)
|
||||
|
||||
@@ -1813,6 +1813,8 @@ void SleighCompile::predefinedSymbols(void)
|
||||
symtab.addSymbol(startsym);
|
||||
EndSymbol *endsym = new EndSymbol("inst_next",getConstantSpace());
|
||||
symtab.addSymbol(endsym);
|
||||
Next2Symbol *next2sym = new Next2Symbol("inst_next2",getConstantSpace());
|
||||
symtab.addSymbol(next2sym);
|
||||
EpsilonSymbol *epsilon = new EpsilonSymbol("epsilon",getConstantSpace());
|
||||
symtab.addSymbol(epsilon);
|
||||
pcode.setConstantSpace(getConstantSpace());
|
||||
@@ -2907,20 +2909,23 @@ ConstructTpl *SleighCompile::setResultStarVarnode(ConstructTpl *ct,StarQuality *
|
||||
/// 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
|
||||
/// 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
|
||||
/// So we check to make sure the value expression doesn't use this symbol.
|
||||
/// Because we are in the middle of parsing, the \b inst_next and \b inst_next2 values have not
|
||||
/// 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 sym is the given context variable affected by the operation
|
||||
/// \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)
|
||||
|
||||
{
|
||||
vector<const PatternValue *> 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)
|
||||
return false;
|
||||
if (dynamic_cast<const Next2InstructionValue *>(vallist[i]) != (const Next2InstructionValue *)0)
|
||||
return false;
|
||||
}
|
||||
// Otherwise we generate a "temporary" change to context instruction (ContextOp)
|
||||
ContextField *field = (ContextField *)sym->getPatternValue();
|
||||
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
|
||||
version 2.2 of Bison. */
|
||||
|
||||
#ifndef YY_YY_SRC_DECOMPILE_CPP_SLGHPARSE_HH_INCLUDED
|
||||
# define YY_YY_SRC_DECOMPILE_CPP_SLGHPARSE_HH_INCLUDED
|
||||
#ifndef YY_YY_SLGHPARSE_HH_INCLUDED
|
||||
# define YY_YY_SLGHPARSE_HH_INCLUDED
|
||||
/* Debug traces. */
|
||||
#ifndef YYDEBUG
|
||||
# define YYDEBUG 0
|
||||
@@ -168,9 +168,10 @@ extern int yydebug;
|
||||
OPERANDSYM = 363,
|
||||
STARTSYM = 364,
|
||||
ENDSYM = 365,
|
||||
MACROSYM = 366,
|
||||
LABELSYM = 367,
|
||||
SUBTABLESYM = 368
|
||||
NEXT2SYM = 366,
|
||||
MACROSYM = 367,
|
||||
LABELSYM = 368,
|
||||
SUBTABLESYM = 369
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -179,7 +180,7 @@ extern int yydebug;
|
||||
|
||||
union YYSTYPE
|
||||
{
|
||||
#line 29 "src/decompile/cpp/slghparse.y" /* yacc.c:1909 */
|
||||
#line 29 "slghparse.y" /* yacc.c:1909 */
|
||||
|
||||
char ch;
|
||||
uintb *i;
|
||||
@@ -212,6 +213,7 @@ union YYSTYPE
|
||||
SubtableSymbol *subtablesym;
|
||||
StartSymbol *startsym;
|
||||
EndSymbol *endsym;
|
||||
Next2Symbol *next2sym;
|
||||
OperandSymbol *operandsym;
|
||||
VarnodeListSymbol *varlistsym;
|
||||
VarnodeSymbol *varsym;
|
||||
@@ -223,7 +225,7 @@ union YYSTYPE
|
||||
FamilySymbol *famsym;
|
||||
SpecificSymbol *specsym;
|
||||
|
||||
#line 212 "src/decompile/cpp/slghparse.hh" /* yacc.c:1909 */
|
||||
#line 214 "slghparse.hh" /* yacc.c:1909 */
|
||||
};
|
||||
|
||||
typedef union YYSTYPE YYSTYPE;
|
||||
@@ -236,4 +238,4 @@ extern YYSTYPE yylval;
|
||||
|
||||
int yyparse (void);
|
||||
|
||||
#endif /* !YY_YY_SRC_DECOMPILE_CPP_SLGHPARSE_HH_INCLUDED */
|
||||
#endif /* !YY_YY_SLGHPARSE_HH_INCLUDED */
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
SubtableSymbol *subtablesym;
|
||||
StartSymbol *startsym;
|
||||
EndSymbol *endsym;
|
||||
Next2Symbol *next2sym;
|
||||
OperandSymbol *operandsym;
|
||||
VarnodeListSymbol *varlistsym;
|
||||
VarnodeSymbol *varsym;
|
||||
@@ -121,6 +122,7 @@
|
||||
%token <operandsym> OPERANDSYM
|
||||
%token <startsym> STARTSYM
|
||||
%token <endsym> ENDSYM
|
||||
%token <next2sym> NEXT2SYM
|
||||
%token <macrosym> MACROSYM
|
||||
%token <labelsym> LABELSYM
|
||||
%token <subtablesym> SUBTABLESYM
|
||||
@@ -331,7 +333,7 @@ contextblock: { $$ = (vector<ContextChange *> *)0; }
|
||||
| '[' contextlist ']' { $$ = $2; }
|
||||
;
|
||||
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 '(' specificsymbol ',' CONTEXTSYM ')' ';' { $$ = $1; slgh->contextSet($1,$4,$6); }
|
||||
| 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; }
|
||||
| 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; }
|
||||
| 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(); }
|
||||
@@ -499,6 +502,7 @@ specificsymbol: VARSYM { $$ = $1; }
|
||||
| OPERANDSYM { $$ = $1; }
|
||||
| STARTSYM { $$ = $1; }
|
||||
| ENDSYM { $$ = $1; }
|
||||
| NEXT2SYM { $$ = $1; }
|
||||
;
|
||||
charstring: CHAR { $$ = new string; (*$$) += $1; }
|
||||
| charstring CHAR { $$ = $1; (*$$) += $2; }
|
||||
@@ -573,6 +577,7 @@ anysymbol: SPACESYM { $$ = $1; }
|
||||
| OPERANDSYM { $$ = $1; }
|
||||
| STARTSYM { $$ = $1; }
|
||||
| ENDSYM { $$ = $1; }
|
||||
| NEXT2SYM { $$ = $1; }
|
||||
| BITSYM { $$ = $1; }
|
||||
;
|
||||
%%
|
||||
|
||||
@@ -165,6 +165,19 @@ public:
|
||||
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 OperandSymbol;
|
||||
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:
|
||||
yylval.endsym = (EndSymbol *)sym;
|
||||
return ENDSYM;
|
||||
case SleighSymbol::next2_symbol:
|
||||
yylval.next2sym = (Next2Symbol *)sym;
|
||||
return NEXT2SYM;
|
||||
case SleighSymbol::subtable_symbol:
|
||||
yylval.subtablesym = (SubtableSymbol *)sym;
|
||||
return SUBTABLESYM;
|
||||
|
||||
@@ -252,6 +252,8 @@ void SymbolTable::restoreSymbolHeader(const Element *el)
|
||||
sym = new StartSymbol();
|
||||
else if (el->getName() == "end_sym_head")
|
||||
sym = new EndSymbol();
|
||||
else if (el->getName() == "next2_sym_head")
|
||||
sym = new Next2Symbol();
|
||||
else if (el->getName() == "subtable_sym_head")
|
||||
sym = new SubtableSymbol();
|
||||
else if (el->getName() == "flowdest_sym_head")
|
||||
@@ -1254,6 +1256,70 @@ void EndSymbol::restoreXml(const Element *el,SleighBase *trans)
|
||||
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)
|
||||
|
||||
{
|
||||
|
||||
@@ -25,7 +25,7 @@ class SleighSymbol {
|
||||
public:
|
||||
enum symbol_type { space_symbol, token_symbol, userop_symbol, value_symbol, valuemap_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,
|
||||
dummy_symbol };
|
||||
private:
|
||||
@@ -391,6 +391,23 @@ public:
|
||||
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 {
|
||||
AddrSpace *const_space;
|
||||
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
|
||||
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
|
||||
<code>inst_start</code> and <code>inst_next</code> as addresses describing the instruction containing the
|
||||
<code>CALLOTHER</code>.
|
||||
<code>inst_start</code>, <code>inst_next</code> and <code>inst_next2</code> as addresses describing the instruction
|
||||
containing the <code>CALLOTHER</code>.
|
||||
</para>
|
||||
<example>
|
||||
<programlisting>
|
||||
|
||||
@@ -1006,6 +1006,10 @@ We list all of the symbols that are predefined by SLEIGH.
|
||||
<td><code>inst_next</code></td>
|
||||
<td>Offset of the address of the next instruction.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>inst_next2</code></td>
|
||||
<td>Offset of the address of the instruction after the next instruction.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>epsilon</code></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
|
||||
either the address of the instruction or the address of the next
|
||||
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>
|
||||
identifiers are address spaces. The <emphasis>epsilon</emphasis>
|
||||
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.
|
||||
</para>
|
||||
</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">
|
||||
<title>Bit Range Assignments</title>
|
||||
<para>
|
||||
@@ -3439,7 +3464,8 @@ by the condition.
|
||||
<para>
|
||||
Because the <emphasis role="bold">delayslot</emphasis> directive
|
||||
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
|
||||
following conventions for interpreting
|
||||
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
|
||||
disassembly action, the <emphasis>inst_next</emphasis> symbol refers
|
||||
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>
|
||||
</sect2>
|
||||
</sect1>
|
||||
|
||||
+16
-8
@@ -349,9 +349,10 @@ specific_symbol[String purpose] returns [SpecificSymbol symbol]
|
||||
: ^(OP_IDENTIFIER s=.) {
|
||||
SleighSymbol sym = pcode.findSymbol($s.getText());
|
||||
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
|
||||
&& sym.getType() != symbol_type.end_symbol
|
||||
&& sym.getType() != symbol_type.next2_symbol
|
||||
&& sym.getType() != symbol_type.operand_symbol
|
||||
&& sym.getType() != symbol_type.epsilon_symbol
|
||||
&& sym.getType() != symbol_type.varnode_symbol) {
|
||||
@@ -839,7 +840,7 @@ pattern_symbol[String purpose] returns [PatternExpression expr]
|
||||
: ^(OP_IDENTIFIER s=.) {
|
||||
SleighSymbol sym = sc.findSymbol($s.getText());
|
||||
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) {
|
||||
OperandSymbol os = (OperandSymbol) sym;
|
||||
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();
|
||||
} else if(sym.getType() == symbol_type.start_symbol
|
||||
|| sym.getType() == symbol_type.end_symbol
|
||||
|| sym.getType() == symbol_type.next2_symbol
|
||||
|| sym.getType() == symbol_type.epsilon_symbol
|
||||
|| sym.getType() == symbol_type.varnode_symbol) {
|
||||
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");
|
||||
}
|
||||
} 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 {
|
||||
@@ -877,9 +879,10 @@ pattern_symbol2[String purpose] returns [PatternExpression expr]
|
||||
: ^(OP_IDENTIFIER s=.) {
|
||||
SleighSymbol sym = sc.findSymbol($s.getText());
|
||||
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
|
||||
|| sym.getType() == symbol_type.end_symbol
|
||||
|| sym.getType() == symbol_type.next2_symbol
|
||||
|| sym.getType() == symbol_type.operand_symbol
|
||||
|| sym.getType() == symbol_type.epsilon_symbol
|
||||
|| sym.getType() == symbol_type.varnode_symbol) {
|
||||
@@ -893,7 +896,7 @@ pattern_symbol2[String purpose] returns [PatternExpression expr]
|
||||
FamilySymbol z = (FamilySymbol) sym;
|
||||
$expr = z.getPatternValue();
|
||||
} 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 {
|
||||
@@ -922,7 +925,7 @@ cstatement[VectorSTL<ContextChange> r]
|
||||
} else if(sym.getType() == symbol_type.context_symbol) {
|
||||
ContextSymbol t = (ContextSymbol) sym;
|
||||
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) {
|
||||
OperandSymbol t = (OperandSymbol) sym;
|
||||
@@ -950,6 +953,7 @@ cstatement[VectorSTL<ContextChange> r]
|
||||
|| sym.getType() == symbol_type.varnodelist_symbol
|
||||
|| sym.getType() == symbol_type.start_symbol
|
||||
|| sym.getType() == symbol_type.end_symbol
|
||||
|| sym.getType() == symbol_type.next2_symbol
|
||||
|| sym.getType() == symbol_type.operand_symbol
|
||||
|| sym.getType() == symbol_type.epsilon_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());
|
||||
} else if(sym.getType() != symbol_type.start_symbol
|
||||
&& sym.getType() != symbol_type.end_symbol
|
||||
&& sym.getType() != symbol_type.next2_symbol
|
||||
&& sym.getType() != symbol_type.operand_symbol
|
||||
&& sym.getType() != symbol_type.epsilon_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 {
|
||||
VarnodeTpl v = ((SpecificSymbol) sym).getVarnode();
|
||||
e.setOutput(find(t), v);
|
||||
@@ -1309,7 +1314,9 @@ jump_symbol[String purpose] returns [VarnodeTpl value]
|
||||
SleighSymbol sym = pcode.findSymbol($s.getText());
|
||||
if (sym == null) {
|
||||
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;
|
||||
$value = new VarnodeTpl(find($s), new ConstTpl(ConstTpl.const_type.j_curspace),
|
||||
ss.getVarnode().getOffset(),
|
||||
@@ -1489,6 +1496,7 @@ expr_apply returns [Object value]
|
||||
}
|
||||
} else if(sym.getType() == symbol_type.start_symbol
|
||||
|| sym.getType() == symbol_type.end_symbol
|
||||
|| sym.getType() == symbol_type.next2_symbol
|
||||
|| sym.getType() == symbol_type.operand_symbol
|
||||
|| sym.getType() == symbol_type.epsilon_symbol
|
||||
|| sym.getType() == symbol_type.varnode_symbol) {
|
||||
|
||||
+4
@@ -573,6 +573,10 @@ public class SleighAssemblerBuilder implements AssemblerBuilder {
|
||||
else if (sym instanceof EndSymbol) {
|
||||
// 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) {
|
||||
// Ignore. We don't do pcode.
|
||||
}
|
||||
|
||||
+77
@@ -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);
|
||||
}
|
||||
}
|
||||
+1
@@ -53,6 +53,7 @@ public class RecursiveDescentSolver {
|
||||
new ContextFieldSolver().register(this);
|
||||
new DivExpressionSolver().register(this);
|
||||
new EndInstructionValueSolver().register(this);
|
||||
new Next2InstructionValueSolver().register(this);
|
||||
new LeftShiftExpressionSolver().register(this);
|
||||
new MinusExpressionSolver().register(this);
|
||||
new MultExpressionSolver().register(this);
|
||||
|
||||
+3
@@ -78,6 +78,9 @@ public abstract class AbstractExpressionMatcher<T extends PatternExpression>
|
||||
if (a instanceof EndInstructionValue) {
|
||||
return true;
|
||||
}
|
||||
if (a instanceof Next2InstructionValue) {
|
||||
return true;
|
||||
}
|
||||
if (a instanceof StartInstructionValue) {
|
||||
return true;
|
||||
}
|
||||
|
||||
+3
@@ -54,6 +54,7 @@ public class AssemblyTreeResolver {
|
||||
|
||||
public static final String INST_START = "inst_start";
|
||||
public static final String INST_NEXT = "inst_next";
|
||||
public static final String INST_NEXT2 = "inst_next2";
|
||||
|
||||
protected final SleighLanguage lang;
|
||||
protected final Address at;
|
||||
@@ -195,6 +196,8 @@ public class AssemblyTreeResolver {
|
||||
return rc;
|
||||
}
|
||||
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);
|
||||
AssemblyResolution ar = rc.backfill(SOLVER, vals);
|
||||
DBG.println("Backfilled final: " + ar);
|
||||
|
||||
+6
@@ -210,6 +210,12 @@ public class ParserWalker {
|
||||
return context.getNaddr();
|
||||
}
|
||||
|
||||
public Address getN2addr() {
|
||||
if (cross_context != null)
|
||||
return cross_context.getN2addr();
|
||||
return context.getN2addr();
|
||||
}
|
||||
|
||||
public AddressSpace getCurSpace() {
|
||||
return context.getCurSpace();
|
||||
}
|
||||
|
||||
+3
-3
@@ -246,7 +246,7 @@ public abstract class PcodeEmit {
|
||||
if (opcode == PcodeOp.BRANCH) {
|
||||
int offsetType = inputs[0].getOffset().getType();
|
||||
if (offsetType == ConstTpl.J_RELATIVE || offsetType == ConstTpl.J_START ||
|
||||
offsetType == ConstTpl.J_NEXT) {
|
||||
offsetType == ConstTpl.J_NEXT || offsetType == ConstTpl.J_NEXT2) {
|
||||
return false;
|
||||
}
|
||||
OpTpl callopt = new OpTpl(PcodeOp.CALL, null, inputs);
|
||||
@@ -269,7 +269,7 @@ public abstract class PcodeEmit {
|
||||
else if (opcode == PcodeOp.CBRANCH) {
|
||||
int offsetType = inputs[0].getOffset().getType();
|
||||
if (offsetType == ConstTpl.J_RELATIVE || offsetType == ConstTpl.J_START ||
|
||||
offsetType == ConstTpl.J_NEXT) {
|
||||
offsetType == ConstTpl.J_NEXT || offsetType == ConstTpl.J_NEXT2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -326,7 +326,7 @@ public abstract class PcodeEmit {
|
||||
if (opcode == PcodeOp.BRANCH || opcode == PcodeOp.CALL) {
|
||||
int offsetType = inputs[0].getOffset().getType();
|
||||
if (offsetType == ConstTpl.J_RELATIVE || offsetType == ConstTpl.J_START ||
|
||||
offsetType == ConstTpl.J_NEXT) {
|
||||
offsetType == ConstTpl.J_NEXT || offsetType == ConstTpl.J_NEXT2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
+6
-1
@@ -89,7 +89,6 @@ public class SleighInstructionPrototype implements InstructionPrototype {
|
||||
private final static Address[] emptyFlow = new Address[0];
|
||||
|
||||
private ContextCache contextCache;
|
||||
// private InstructionContext instructionContextCache;
|
||||
private int length;
|
||||
private ConstructState rootState;
|
||||
private ConstructState mnemonicState; // state for print mnemonic
|
||||
@@ -236,6 +235,9 @@ public class SleighInstructionPrototype implements InstructionPrototype {
|
||||
if (destType == ConstTpl.J_NEXT) {
|
||||
flags = BRANCH_TO_END;
|
||||
}
|
||||
else if (destType == ConstTpl.J_NEXT2) {
|
||||
flags = JUMPOUT;
|
||||
}
|
||||
else if ((destType != ConstTpl.J_START) && (destType != ConstTpl.J_RELATIVE)) {
|
||||
flags = JUMPOUT;
|
||||
}
|
||||
@@ -674,6 +676,9 @@ public class SleighInstructionPrototype implements InstructionPrototype {
|
||||
Address addr = getHandleAddr(hand, parsecontext.getAddr().getAddressSpace());
|
||||
res.add(addr);
|
||||
}
|
||||
else if (rec.op.getInput()[0].getOffset().getType() == ConstTpl.J_NEXT2) {
|
||||
res.add(parsecontext.getN2addr());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+121
-5
@@ -21,8 +21,7 @@ import ghidra.app.plugin.processors.sleigh.symbol.OperandSymbol;
|
||||
import ghidra.app.plugin.processors.sleigh.symbol.TripleSymbol;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.lang.*;
|
||||
import ghidra.program.model.mem.MemBuffer;
|
||||
import ghidra.program.model.mem.MemoryAccessException;
|
||||
import ghidra.program.model.mem.*;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -33,8 +32,9 @@ import ghidra.program.model.mem.MemoryAccessException;
|
||||
|
||||
public class SleighParserContext implements ParserContext {
|
||||
private MemBuffer memBuffer;
|
||||
private Address addr; // Address of start of instruction
|
||||
private Address nextInstrAddr; // Address of next instruction
|
||||
private Address addr; // Address of start of instruction (inst_start)
|
||||
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 destAddr; // corresponds to inst_dest for call-fixup use
|
||||
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 nAddr = address to which 'inst_next' resolves
|
||||
* @param rAddr = special address associated with original call
|
||||
@@ -172,22 +173,99 @@ public class SleighParserContext implements ParserContext {
|
||||
return handle;
|
||||
}
|
||||
|
||||
/**
|
||||
* get address of current instruction
|
||||
* @return address of current instruction
|
||||
*/
|
||||
public Address getAddr() {
|
||||
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() {
|
||||
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() {
|
||||
return addr.getAddressSpace();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get constant address space
|
||||
* @return constant address space
|
||||
*/
|
||||
public AddressSpace getConstSpace() {
|
||||
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() {
|
||||
return memBuffer;
|
||||
}
|
||||
@@ -251,6 +329,44 @@ public class SleighParserContext implements ParserContext {
|
||||
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
|
||||
* @param bytestart is the index of the first byte to fetch
|
||||
|
||||
+68
@@ -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]";
|
||||
}
|
||||
}
|
||||
+2
@@ -51,6 +51,8 @@ public abstract class PatternExpression {
|
||||
res = new StartInstructionValue();
|
||||
else if (nm.equals("end_exp"))
|
||||
res = new EndInstructionValue();
|
||||
else if (nm.equals("next2_exp"))
|
||||
res = new Next2InstructionValue();
|
||||
else if (nm.equals("plus_exp"))
|
||||
res = new PlusExpression();
|
||||
else if (nm.equals("sub_exp"))
|
||||
|
||||
+68
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
+4
-2
@@ -19,6 +19,8 @@
|
||||
*/
|
||||
package ghidra.app.plugin.processors.sleigh.symbol;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import ghidra.app.plugin.processors.sleigh.SleighException;
|
||||
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
|
||||
import ghidra.program.model.lang.UnknownInstructionException;
|
||||
@@ -26,8 +28,6 @@ import ghidra.util.xml.SpecXmlUtils;
|
||||
import ghidra.xml.XmlElement;
|
||||
import ghidra.xml.XmlPullParser;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
@@ -152,6 +152,8 @@ public class SymbolTable {
|
||||
sym = new StartSymbol();
|
||||
else if (el.getName().equals("end_sym_head"))
|
||||
sym = new EndSymbol();
|
||||
else if (el.getName().equals("next2_sym_head"))
|
||||
sym = new Next2Symbol();
|
||||
else if (el.getName().equals("subtable_sym_head"))
|
||||
sym = new SubtableSymbol();
|
||||
else
|
||||
|
||||
+16
-8
@@ -39,14 +39,15 @@ public class ConstTpl {
|
||||
public static final int HANDLE = 1;
|
||||
public static final int J_START = 2;
|
||||
public static final int J_NEXT = 3;
|
||||
public static final int J_CURSPACE = 4;
|
||||
public static final int J_CURSPACE_SIZE = 5;
|
||||
public static final int SPACEID = 6;
|
||||
public static final int J_RELATIVE = 7;
|
||||
public static final int J_FLOWREF = 8;
|
||||
public static final int J_FLOWREF_SIZE = 9;
|
||||
public static final int J_FLOWDEST = 10;
|
||||
public static final int J_FLOWDEST_SIZE = 11;
|
||||
public static final int J_NEXT2 = 4;
|
||||
public static final int J_CURSPACE = 5;
|
||||
public static final int J_CURSPACE_SIZE = 6;
|
||||
public static final int SPACEID = 7;
|
||||
public static final int J_RELATIVE = 8;
|
||||
public static final int J_FLOWREF = 9;
|
||||
public static final int J_FLOWREF_SIZE = 10;
|
||||
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_OFFSET = 1;
|
||||
@@ -143,6 +144,8 @@ public class ConstTpl {
|
||||
return walker.getAddr().getOffset();
|
||||
case J_NEXT:
|
||||
return walker.getNaddr().getOffset();
|
||||
case J_NEXT2:
|
||||
return walker.getN2addr().getOffset();
|
||||
case J_FLOWREF:
|
||||
return walker.getFlowRefAddr().getOffset();
|
||||
case J_FLOWREF_SIZE:
|
||||
@@ -315,6 +318,9 @@ public class ConstTpl {
|
||||
else if (typestr.equals("next")) {
|
||||
type = J_NEXT;
|
||||
}
|
||||
else if (typestr.equals("next2")) {
|
||||
type = J_NEXT2;
|
||||
}
|
||||
else if (typestr.equals("curspace")) {
|
||||
type = J_CURSPACE;
|
||||
}
|
||||
@@ -379,6 +385,8 @@ public class ConstTpl {
|
||||
return "[flowref_size]";
|
||||
case J_NEXT:
|
||||
return "[next]";
|
||||
case J_NEXT2:
|
||||
return "[next2]";
|
||||
case J_START:
|
||||
return "[start]";
|
||||
case J_RELATIVE:
|
||||
|
||||
-1
@@ -1,6 +1,5 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
-1
@@ -1,6 +1,5 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
+4
-1
@@ -289,6 +289,8 @@ public class SleighCompile extends SleighBase {
|
||||
symtab.addSymbol(startsym);
|
||||
EndSymbol endsym = new EndSymbol(location, "inst_next", getConstantSpace());
|
||||
symtab.addSymbol(endsym);
|
||||
Next2Symbol next2sym = new Next2Symbol(location, "inst_next2", getConstantSpace());
|
||||
symtab.addSymbol(next2sym);
|
||||
EpsilonSymbol epsilon = new EpsilonSymbol(location, "epsilon", getConstantSpace());
|
||||
symtab.addSymbol(epsilon);
|
||||
}
|
||||
@@ -1280,7 +1282,8 @@ public class SleighCompile extends SleighBase {
|
||||
VectorSTL<PatternValue> vallist = new VectorSTL<>();
|
||||
pe.listValues(vallist);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,6 +1,5 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -32,6 +31,7 @@ class Yylval {
|
||||
OperandSymbol operandsym;
|
||||
StartSymbol startsym;
|
||||
EndSymbol endsym;
|
||||
Next2Symbol next2sym;
|
||||
SubtableSymbol subtablesym;
|
||||
MacroSymbol macrosym;
|
||||
LabelSymbol labelsym;
|
||||
|
||||
-1
@@ -1,6 +1,5 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
-1
@@ -1,6 +1,5 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
-1
@@ -1,6 +1,5 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
-1
@@ -1,6 +1,5 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
-1
@@ -1,6 +1,5 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
-1
@@ -1,6 +1,5 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
-1
@@ -1,6 +1,5 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user