diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/address.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/address.cc index aa16170c7c..2581efe030 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/address.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/address.cc @@ -712,6 +712,22 @@ int4 mostsigbit_set(uintb val) return res; } +/// Count the number (population) bits set. +/// \param val is the given value +/// \return the number of one bits +int4 popcount(uintb val) + +{ + val = (val & 0x5555555555555555L) + ((val >> 1) & 0x5555555555555555L); + val = (val & 0x3333333333333333L) + ((val >> 2) & 0x3333333333333333L); + val = (val & 0x0f0f0f0f0f0f0f0fL) + ((val >> 4) & 0x0f0f0f0f0f0f0f0fL); + val = (val & 0x00ff00ff00ff00ffL) + ((val >> 8) & 0x00ff00ff00ff00ffL); + val = (val & 0x0000ffff0000ffffL) + ((val >> 16) & 0x0000ffff0000ffffL); + int4 res = (int4)(val & 0xff); + res += (int4)((val >> 32) & 0xff); + return res; +} + /// Count the number of more significant zero bits before the most significant /// one bit in the representation of the given value; /// \param val is the given value diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/address.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/address.hh index 1f8e9159ea..06555078b0 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/address.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/address.hh @@ -495,6 +495,7 @@ extern void byte_swap(intb &val,int4 size); ///< Swap bytes in the given value extern uintb byte_swap(uintb val,int4 size); ///< Return the given value with bytes swapped extern int4 leastsigbit_set(uintb val); ///< Return index of least significant bit set in given value extern int4 mostsigbit_set(uintb val); ///< Return index of most significant bit set in given value +extern int4 popcount(uintb val); ///< Return the number of one bits in the given value extern int4 count_leading_zeros(uintb val); ///< Return the number of leading zero bits in the given value extern uintb coveringmask(uintb val); ///< Return a mask that \e covers the given value diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.cc index 1731e64e53..207a41b2b5 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.cc @@ -3053,6 +3053,34 @@ void ActionDeadCode::propagateConsumed(vector &worklist) pushConsumed(a,op->getIn(0),worklist); pushConsumed(a,op->getIn(1),worklist); break; + case CPUI_INSERT: + a = 1; + a <<= (int4)op->getIn(3)->getOffset(); + a -= 1; // Insert mask + pushConsumed(a,op->getIn(1),worklist); + a <<= (int4)op->getIn(2)->getOffset(); + pushConsumed(outc & ~a, op->getIn(0), worklist); + b = (outc == 0) ? 0 : ~((uintb)0); + pushConsumed(b,op->getIn(2), worklist); + pushConsumed(b,op->getIn(3), worklist); + break; + case CPUI_EXTRACT: + a = 1; + a <<= (int4)op->getIn(2)->getOffset(); + a -= 1; // Extract mask + a &= outc; // Consumed bits of mask + a <<= (int4)op->getIn(1)->getOffset(); + pushConsumed(a,op->getIn(0),worklist); + b = (outc == 0) ? 0 : ~((uintb)0); + pushConsumed(b,op->getIn(1), worklist); + pushConsumed(b,op->getIn(2), worklist); + break; + case CPUI_POPCOUNT: + a = 16 * op->getIn(0)->getSize() - 1; // Mask for possible bits that could be set + a &= outc; // Of the bits that could be set, which are consumed + b = (a == 0) ? 0 : ~((uintb)0); // if any consumed, treat all input bits as consumed + pushConsumed(b,op->getIn(0), worklist); + break; default: a = (outc==0) ? 0 : ~((uintb)0); // all or nothing for(int4 i=0;inumInput();++i) diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/dynamic.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/dynamic.cc index 1ce25706ee..e0c3febd07 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/dynamic.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/dynamic.cc @@ -55,7 +55,7 @@ uint4 DynamicHash::transtable[] = { 0, // CAST is skipped CPUI_INT_ADD, CPUI_INT_ADD, // PTRADD and PTRSUB hash same as INT_ADD - CPUI_SEGMENTOP, CPUI_CPOOLREF, CPUI_NEW + CPUI_SEGMENTOP, CPUI_CPOOLREF, CPUI_NEW, CPUI_INSERT, CPUI_EXTRACT, CPUI_POPCOUNT }; diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/op.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/op.cc index 6e18cd03de..d363a42d4f 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/op.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/op.cc @@ -493,6 +493,11 @@ uintb PcodeOp::getNZMaskLocal(bool cliploop) const val = (getIn(1)->getNZMask()-1); // Result is less than modulus resmask = coveringmask(val); break; + case CPUI_POPCOUNT: + sz1 = popcount(getIn(0)->getNZMask()); + resmask = coveringmask((uintb)sz1); + resmask &= fullmask; + break; case CPUI_SUBPIECE: resmask = getIn(0)->getNZMask(); resmask >>= 8*getIn(1)->getOffset(); diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/opbehavior.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/opbehavior.cc index 5f66673ccb..184952c7fd 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/opbehavior.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/opbehavior.cc @@ -99,6 +99,9 @@ void OpBehavior::registerInstructions(vector &inst,const Translate inst[CPUI_SEGMENTOP] = new OpBehavior(CPUI_SEGMENTOP,false,true); inst[CPUI_CPOOLREF] = new OpBehavior(CPUI_CPOOLREF,false,true); inst[CPUI_NEW] = new OpBehavior(CPUI_NEW,false,true); + inst[CPUI_INSERT] = new OpBehavior(CPUI_INSERT,false,true); + inst[CPUI_EXTRACT] = new OpBehavior(CPUI_EXTRACT,false,true); + inst[CPUI_POPCOUNT] = new OpBehaviorPopcount(); } /// \param sizeout is the size of the output in bytes @@ -725,3 +728,9 @@ uintb OpBehaviorSubpiece::evaluateBinary(int4 sizeout,int4 sizein,uintb in1,uint return res; } +uintb OpBehaviorPopcount::evaluateUnary(int4 sizeout,int4 sizein,uintb in1) const + +{ + return (uintb)popcount(in1); +} + diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/opbehavior.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/opbehavior.hh index 4ddd20fc90..61573704c3 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/opbehavior.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/opbehavior.hh @@ -502,5 +502,11 @@ public: virtual uintb evaluateBinary(int4 sizeout,int4 sizein,uintb in1,uintb in2) const; }; +/// CPUI_POPCOUNT behavior +class OpBehaviorPopcount : public OpBehavior { +public: + OpBehaviorPopcount(void) : OpBehavior(CPUI_POPCOUNT,true) {} ///< Constructor + virtual uintb evaluateUnary(int4 sizeout,int4 sizein,uintb in1) const; +}; #endif diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/opcodes.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/opcodes.cc index 941fa1b017..d116fe62da 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/opcodes.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/opcodes.cc @@ -41,14 +41,15 @@ static const char *opcode_name[] = { "FLOAT_ABS", "FLOAT_SQRT", "INT2FLOAT", "FLOAT2FLOAT", "TRUNC", "CEIL", "FLOOR", "ROUND", "BUILD", "DELAY_SLOT", "PIECE", "SUBPIECE", "CAST", - "LABEL", "CROSSBUILD", "SEGMENTOP", "CPOOLREF", "NEW" + "LABEL", "CROSSBUILD", "SEGMENTOP", "CPOOLREF", "NEW", + "INSERT", "EXTRACT", "POPCOUNT" }; static const int4 opcode_indices[] = { 0, 39, 37, 40, 38, 4, 6, 60, 7, 8, 9, 64, 5, 57, 1, 68, 66, - 61, 55, 52, 47, 48, 41, 43, 44, 49, 46, 51, 42, 53, 50, 58, + 61, 71, 55, 52, 47, 48, 41, 43, 44, 49, 46, 51, 42, 53, 50, 58, 70, 54, 24, 19, 27, 21, 33, 11, 29, 15, 16, 32, 25, 12, 28, 35, 30, - 23, 22, 34, 18, 13, 14, 36, 31, 20, 26, 17, 65, 2, 69, 62, 10, 59, + 23, 22, 34, 18, 13, 14, 36, 31, 20, 26, 17, 65, 2, 69, 62, 72, 10, 59, 67, 3, 63, 56, 45 }; diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/opcodes.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/opcodes.hh index 0099c13db4..14ec997724 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/opcodes.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/opcodes.hh @@ -120,8 +120,11 @@ enum OpCode { CPUI_SEGMENTOP = 67, ///< Look-up a \e segmented address CPUI_CPOOLREF = 68, ///< Recover a value from the \e constant \e pool CPUI_NEW = 69, ///< Allocate a new object (new) + CPUI_INSERT = 70, ///< Insert a bit-range + CPUI_EXTRACT = 71, ///< Extract a bit-range + CPUI_POPCOUNT = 72, ///< Count the 1-bits - CPUI_MAX = 70 ///< Value indicating the end of the op-code values + CPUI_MAX = 73 ///< Value indicating the end of the op-code values }; extern const char *get_opname(OpCode opc); ///< Convert an OpCode to the name as a string diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/printc.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/printc.cc index 2b233c46f8..1902446b34 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/printc.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/printc.cc @@ -970,6 +970,18 @@ void PrintC::opNewOp(const PcodeOp *op) pushVnImplied(vn0,op,mods); } +void PrintC::opInsertOp(const PcodeOp *op) + +{ + opFunc(op); // If no other way to print it, print as functional operator +} + +void PrintC::opExtractOp(const PcodeOp *op) + +{ + opFunc(op); // If no other way to print it, print as functional operator +} + /// \brief Push a constant with an integer data-type to the RPN stack /// /// Various checks are made to see if the integer should be printed as an \e equate diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/printc.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/printc.hh index 65f67031ce..c3daf45207 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/printc.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/printc.hh @@ -290,6 +290,9 @@ public: virtual void opSegmentOp(const PcodeOp *op); virtual void opCpoolRefOp(const PcodeOp *op); virtual void opNewOp(const PcodeOp *op); + virtual void opInsertOp(const PcodeOp *op); + virtual void opExtractOp(const PcodeOp *op); + virtual void opPopcountOp(const PcodeOp *op) { opFunc(op); } }; #endif diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/printlanguage.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/printlanguage.hh index cf307ae772..549edd6814 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/printlanguage.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/printlanguage.hh @@ -538,6 +538,9 @@ public: virtual void opSegmentOp(const PcodeOp *op)=0; ///< Emit a SEGMENTOP operator virtual void opCpoolRefOp(const PcodeOp *op)=0; ///< Emit a CPOOLREF operator virtual void opNewOp(const PcodeOp *op)=0; ///< Emit a NEW operator + virtual void opInsertOp(const PcodeOp *op)=0; ///< Emit an INSERT operator + virtual void opExtractOp(const PcodeOp *op)=0; ///< Emit an EXTRACT operator + virtual void opPopcountOp(const PcodeOp *op)=0; ///< Emit a POPCOUNT operator static int4 mostNaturalBase(uintb val); ///< Determine the most natural base for an integer static void formatBinary(ostream &s,uintb val); ///< Print a number in binary form diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/slgh_compile.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/slgh_compile.cc index 6068f08ca7..f6ae7d272c 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/slgh_compile.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/slgh_compile.cc @@ -734,6 +734,9 @@ void ConsistencyChecker::printOpName(ostream &s,OpTpl *op) case CPUI_NEW: s << "New object(newobject)"; break; + case CPUI_POPCOUNT: + s << "Count bits(popcount)"; + break; default: break; } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/slghparse.y b/Ghidra/Features/Decompiler/src/decompile/cpp/slghparse.y index b536307a40..8626a9e540 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/slghparse.y +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/slghparse.y @@ -93,7 +93,7 @@ %right '!' '~' %token OP_ZEXT OP_CARRY OP_BORROW OP_SEXT OP_SCARRY OP_SBORROW OP_NAN OP_ABS %token OP_SQRT OP_CEIL OP_FLOOR OP_ROUND OP_INT2FLOAT OP_FLOAT2FLOAT -%token OP_TRUNC OP_CPOOLREF OP_NEW +%token OP_TRUNC OP_CPOOLREF OP_NEW OP_POPCOUNT %token BADINTEGER GOTO_KEY CALL_KEY RETURN_KEY IF_KEY %token DEFINE_KEY ATTACH_KEY MACRO_KEY SPACE_KEY TYPE_KEY RAM_KEY DEFAULT_KEY @@ -436,9 +436,10 @@ expr: varnode { $$ = new ExprTree($1); } | OP_TRUNC '(' expr ')' { $$ = slgh->pcode.createOp(CPUI_FLOAT_TRUNC,$3); } | OP_CEIL '(' expr ')' { $$ = slgh->pcode.createOp(CPUI_FLOAT_CEIL,$3); } | OP_FLOOR '(' expr ')' { $$ = slgh->pcode.createOp(CPUI_FLOAT_FLOOR,$3); } - | OP_ROUND '(' expr ')' { $$ = slgh->pcode.createOp(CPUI_FLOAT_ROUND,$3); }; - | OP_NEW '(' expr ')' { $$ = slgh->pcode.createOp(CPUI_NEW,$3); }; + | OP_ROUND '(' expr ')' { $$ = slgh->pcode.createOp(CPUI_FLOAT_ROUND,$3); } + | OP_NEW '(' expr ')' { $$ = slgh->pcode.createOp(CPUI_NEW,$3); } | OP_NEW '(' expr ',' expr ')' { $$ = slgh->pcode.createOp(CPUI_NEW,$3,$5); } + | OP_POPCOUNT '(' expr ')' { $$ = slgh->pcode.createOp(CPUI_POPCOUNT,$3); } | specificsymbol '(' integervarnode ')' { $$ = slgh->pcode.createOp(CPUI_SUBPIECE,new ExprTree($1->getVarnode()),new ExprTree($3)); } | specificsymbol ':' INTEGER { $$ = slgh->pcode.createBitRange($1,0,(uint4)(*$3 * 8)); delete $3; } | specificsymbol '[' INTEGER ',' INTEGER ']' { $$ = slgh->pcode.createBitRange($1,(uint4)*$3,(uint4)*$5); delete $3, delete $5; } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/slghscan.l b/Ghidra/Features/Decompiler/src/decompile/cpp/slghscan.l index 4b571fd81a..0675c29872 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/slghscan.l +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/slghscan.l @@ -637,6 +637,7 @@ with { BEGIN(pattern); withsection = 1; slgh->calcContextLayout(); return WITH trunc { return OP_TRUNC; } cpool { return OP_CPOOLREF; } newobject { return OP_NEW; } +popcount { return OP_POPCOUNT; } if { return IF_KEY; } goto { return GOTO_KEY; } call { return CALL_KEY; } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/typeop.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/typeop.cc index 3ca75d8eec..b67dc33eed 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/typeop.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/typeop.cc @@ -100,6 +100,9 @@ void TypeOp::registerInstructions(vector &inst,TypeFactory *tlst, inst[CPUI_SEGMENTOP] = new TypeOpSegment(tlst); inst[CPUI_CPOOLREF] = new TypeOpCpoolref(tlst); inst[CPUI_NEW] = new TypeOpNew(tlst); + inst[CPUI_INSERT] = new TypeOpInsert(tlst); + inst[CPUI_EXTRACT] = new TypeOpExtract(tlst); + inst[CPUI_POPCOUNT] = new TypeOpPopcount(tlst); } /// Change basic data-type info (signed vs unsigned) and operator names ( '>>' vs '>>>' ) @@ -1809,3 +1812,40 @@ void TypeOpNew::printRaw(ostream &s,const PcodeOp *op) } s << ')'; } + +TypeOpInsert::TypeOpInsert(TypeFactory *t) + : TypeOpFunc(t,CPUI_INSERT,"INSERT",TYPE_UNKNOWN,TYPE_INT) +{ + opflags = PcodeOp::special; + behave = new OpBehavior(CPUI_INSERT,false,true); // Dummy behavior +} + +Datatype *TypeOpInsert::getInputLocal(const PcodeOp *op,int4 slot) const + +{ + if (slot == 0) + return tlst->getBase(op->getIn(slot)->getSize(),TYPE_UNKNOWN); + return TypeOpFunc::getInputLocal(op, slot); +} + +TypeOpExtract::TypeOpExtract(TypeFactory *t) + : TypeOpFunc(t,CPUI_EXTRACT,"EXTRACT",TYPE_INT,TYPE_INT) +{ + opflags = PcodeOp::special; + behave = new OpBehavior(CPUI_EXTRACT,false,true); // Dummy behavior +} + +Datatype *TypeOpExtract::getInputLocal(const PcodeOp *op,int4 slot) const + +{ + if (slot == 0) + return tlst->getBase(op->getIn(slot)->getSize(),TYPE_UNKNOWN); + return TypeOpFunc::getInputLocal(op, slot); +} + +TypeOpPopcount::TypeOpPopcount(TypeFactory *t) + : TypeOpFunc(t,CPUI_POPCOUNT,"POPCOUNT",TYPE_INT,TYPE_UNKNOWN) +{ + opflags = PcodeOp::unary; + behave = new OpBehaviorPopcount(); +} diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/typeop.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/typeop.hh index 8d3e163e1b..87f5e8bea8 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/typeop.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/typeop.hh @@ -777,4 +777,28 @@ public: virtual void push(PrintLanguage *lng,const PcodeOp *op) const { lng->opNewOp(op); } virtual void printRaw(ostream &s,const PcodeOp *op); }; + +/// \brief Information about the INSERT op-code +class TypeOpInsert : public TypeOpFunc { +public: + TypeOpInsert(TypeFactory *t); ///< Constructor + virtual Datatype *getInputLocal(const PcodeOp *op,int4 slot) const; + virtual void push(PrintLanguage *lng,const PcodeOp *op) const { lng->opInsertOp(op); } +}; + +/// \brief Information about the EXTRACT op-code +class TypeOpExtract : public TypeOpFunc { +public: + TypeOpExtract(TypeFactory *t); ///< Constructor + virtual Datatype *getInputLocal(const PcodeOp *op,int4 slot) const; + virtual void push(PrintLanguage *lng,const PcodeOp *op) const { lng->opExtractOp(op); } +}; + +/// \brief Information about the POPCOUNT op-code +class TypeOpPopcount : public TypeOpFunc { +public: + TypeOpPopcount(TypeFactory *t); ///< Constructor + virtual void push(PrintLanguage *lng,const PcodeOp *op) const { lng->opPopcountOp(op); } +}; + #endif