GP-2493 Bitfield support in the Decompiler

This commit is contained in:
caheckman
2025-09-05 00:01:44 +00:00
parent edde4a82ec
commit 402d10d6cc
61 changed files with 5683 additions and 887 deletions
@@ -105,6 +105,7 @@ model {
include "merge.cc"
include "double.cc"
include "constseq.cc"
include "bitfield.cc"
include "coreaction.cc"
include "condexe.cc"
include "override.cc"
@@ -12,6 +12,8 @@ src/decompile/.cproject||GHIDRA||||END|
src/decompile/cpp/.gitignore||GHIDRA||||END|
src/decompile/cpp/Doxyfile||GHIDRA|||Most of this file is autogenerated by doxygen which falls under the GPL - output from GPL products are NOT GPL! - mjbell4|END|
src/decompile/cpp/Makefile||GHIDRA||||END|
src/decompile/datatests/bitfields.xml||GHIDRA||||END|
src/decompile/datatests/bitfields2.xml||GHIDRA||||END|
src/decompile/datatests/boolless.xml||GHIDRA||||END|
src/decompile/datatests/ccmp.xml||GHIDRA||||END|
src/decompile/datatests/concat.xml||GHIDRA||||END|
@@ -83,7 +83,7 @@ DECCORE=capability architecture options graph cover block cast typeop database c
variable varmap jumptable emulate emulateutil flow userop expression multiprecision \
funcdata funcdata_block funcdata_op funcdata_varnode unionresolve pcodeinject \
heritage prefersplit rangeutil ruleaction subflow blockaction merge double \
transform constseq coreaction condexe override dynamic crc32 prettyprint \
transform constseq bitfield coreaction condexe override dynamic crc32 prettyprint \
printlanguage printc printjava memstate opbehavior paramid signature $(COREEXT_NAMES)
# Files used for any project that use the sleigh decoder
SLEIGH= sleigh pcodeparse pcodecompile sleighbase slghsymbol \
@@ -627,6 +627,246 @@ void RangeList::decode(Decoder &decoder)
decoder.closeElement(elemId);
}
BitRange::BitRange(const BitRange &op2,int4 off,int4 sz)
{
byteOffset = off;
byteSize = sz;
numBits = op2.numBits;
isBigEndian = op2.isBigEndian;
leastSigBit = translateLSB(op2);
}
/// Both the byte container and the bit range are compared and must be equal to return 0.
/// \param op2 is the other bit range to compare with
/// \return -1, 0, or 1 to establish ordering the two ranges
int4 BitRange::compare(const BitRange &op2) const
{
if (byteOffset != op2.byteOffset)
return (byteOffset < op2.byteOffset) ? -1:1;
if (byteSize != op2.byteSize)
return (byteSize < op2.byteSize) ? -1 : 1;
if (leastSigBit != op2.leastSigBit)
return (leastSigBit < op2.leastSigBit) ? -1:1;
if (numBits != op2.numBits)
return (numBits < op2.numBits) ? -1:1;
return 0;
}
/// The returned result is directly comparable with \b leastSigBit for determining order/overlap.
/// \param op2 is the other BitRange to translate into \b this frame
/// \return the translated value of op2.leastSigBit
int4 BitRange::translateLSB(const BitRange &op2) const
{
int4 op2Sig = op2.leastSigBit;
if (isBigEndian) {
int4 thisPos = byteOffset + byteSize;
int4 op2Pos = op2.byteOffset + op2.byteSize;
op2Sig += 8 * (thisPos - op2Pos);
}
else {
op2Sig += 8 * (op2.byteOffset - byteOffset);
}
return op2Sig;
}
/// Return:
/// - -1 if \b this should come before (no intersection)
/// - 0 if \b this and op2 are the same bitrange
/// - 1 if \b this should come after (no intersection)
/// - 2 if \b this is contained in op2
/// - 3 if op2 is contained in \b this
/// - 4 if partial overlap
///
/// \param op2 is the other range to compare
/// \return the intersection code
int4 BitRange::overlapTest(const BitRange &op2) const
{
int4 op2Sig = translateLSB(op2);
int4 thisMost = leastSigBit + numBits;
int4 op2Most = op2Sig + op2.numBits;
if (isBigEndian) {
if (leastSigBit >= op2Most) return -1;
if (op2Sig >= thisMost) return 1;
}
else {
if (thisMost <= op2Sig) return -1;
if (op2Most <= leastSigBit) return 1;
}
// Reaching here we have some kind of intersection
if (leastSigBit == op2Sig && thisMost == op2Most) return 0;
if (op2Sig <= leastSigBit && op2Most >= thisMost) return 2; /// this contained in op2
if (leastSigBit <= op2Sig && thisMost >= op2Most) return 3; /// op2 contained in this
return 4;
}
/// The byte container for \b this does not change only \b leastSigBit and \b numBits.
/// If the intersection is empty, \b numBits is set to 0.
/// \param op2 is the bit range to intersect with \b this.
void BitRange::intersection(const BitRange &op2)
{
int4 op2Sig = translateLSB(op2);
int4 op2Most = op2Sig + op2.numBits;
int4 thisMost = leastSigBit + numBits;
if (op2Sig > leastSigBit) {
numBits -= (op2Sig - leastSigBit);
leastSigBit = op2Sig;
}
if (op2Most < thisMost) {
numBits -= (thisMost - op2Most);
}
if (numBits < 0) {
leastSigBit = 0;
numBits = 0;
}
}
/// The range of bits is intersected with the 1-bits of the mask. The resulting
/// range is the minimal cover of the bits in the intersection.
/// \param mask is the mask to intersect with
void BitRange::intersectMask(uintb mask)
{
mask &= getMask();
if (mask == 0) {
leastSigBit = 0;
numBits = 0;
return;
}
int4 newLeastSig = leastsigbit_set(mask);
int4 newMostSig = mostsigbit_set(mask) + 1;
int4 thisMost = leastSigBit + numBits;
if (newLeastSig > leastSigBit) {
numBits -= (newLeastSig - leastSigBit);
leastSigBit = newLeastSig;
}
if (newMostSig < thisMost) {
numBits -= (thisMost - newMostSig);
}
}
/// The bit range is shifted to the left by the given amount.
/// \param leftShiftAmount is the amount to shift the range by
void BitRange::shift(int4 leftShiftAmount)
{
leastSigBit += leftShiftAmount;
int4 most = leastSigBit + numBits;
if (leastSigBit < 0) {
numBits += leastSigBit;
leastSigBit = 0;
}
else if (most > byteSize * 8) {
numBits -= (most - byteSize * 8);
}
if (numBits < 0) {
leastSigBit = 0;
numBits = 0;
}
}
/// The number of bits may be affected.
/// \param num is the number of bytes to truncate
void BitRange::truncateMostSigBytes(int4 num)
{
if (isBigEndian) {
byteOffset += num;
}
byteSize -= num;
int4 maxOffset = leastSigBit + numBits;
if (maxOffset > byteSize * 8)
numBits -= (maxOffset - byteSize * 8);
if (numBits < 0)
numBits = 0;
}
/// \param num is the number of bytes to truncate
void BitRange::truncateLeastSigBytes(int4 num)
{
if (!isBigEndian)
byteOffset += num;
byteSize -= num;
leastSigBit -= num * 8;
if (leastSigBit < 0) {
numBits = numBits + leastSigBit;
leastSigBit = 0;
if (numBits < 0)
numBits = 0;
}
}
/// Only the container is affected, the bit range itself does not change.
/// \param num is the number of bytes to add
void BitRange::extendBytes(int4 num)
{
if (isBigEndian)
byteOffset -= num;
byteSize += num;
}
/// The bit-mask is aligned with the byte container.
/// \return the bit-mask describing \b this range
uintb BitRange::getMask(void) const
{
uintb res;
if (numBits >= sizeof(uintb)*8)
res = 0;
else {
res = 1;
res <<= numBits;
}
res -= 1;
res <<= leastSigBit;
return res;
}
/// \return \b true if the beginning and end of the range fall on byte boundaries
bool BitRange::isByteRange(void) const
{
if ((numBits & 7) != 0) return false;
if ((leastSigBit & 7) != 0) return false;
return true;
}
/// \return \b true if the most significant bit of the field and the container are the same
bool BitRange::isMostSignificant(void) const
{
return 8*byteSize == leastSigBit + numBits;
}
void BitRange::minimizeContainer(void)
{
int4 trunc = leastSigBit / 8;
if (isBigEndian)
byteSize -= trunc;
else
byteOffset += trunc;
leastSigBit &= 7;
int4 num = byteSize - ((leastSigBit + numBits + 7) / 8);
if (num > 0) {
if (isBigEndian)
byteOffset += num;
byteSize -= num;
}
}
void BitRange::expandToMost(void)
{
numBits = 8*byteSize - leastSigBit; // Increase number of bits to maximum that still fits
}
#ifdef UINTB4
uintb uintbmasks[9] = { 0, 0xff, 0xffff, 0xffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff };
#else
@@ -675,6 +915,22 @@ uintb sign_extend(uintb in,int4 sizein,int4 sizeout)
return res;
}
/// \param val is the value to extend
/// \param numbits is the number of bits in the value
/// \param size is the integer size in bytes
/// \return the extended value
uintb extend_signbit(uintb val,int4 numbits,int4 size)
{
if (numbits < size * 8) {
int4 sa = 8*sizeof(intb) - numbits;
intb sval = val;
val = (sval << sa) >> sa;
val &= calc_mask(size);
}
return val;
}
/// Swap the least significant \b size bytes in \b val
/// \param val is a reference to the value to swap
/// \param size is the number of bytes to swap
@@ -253,6 +253,37 @@ public:
void decode(Decoder &decoder); ///< Decode \b this RangeList from a \<rangelist> element
};
/// \brief An endian aware range of bits contained in a contiguous set of bytes
class BitRange {
public:
int4 byteOffset; ///< Byte offset of the region containing the range
int4 byteSize; ///< Size of the region in bytes
int4 leastSigBit; ///< Least significant bit of the bit-range within its region
int4 numBits; ///< Number of bits in the range
bool isBigEndian; ///< Is the underlying encoding big endian
BitRange(void) { byteOffset = -1; byteSize = -1; leastSigBit = -1; numBits = -1; isBigEndian = false; } ///< Construct \e undefined range
BitRange(int4 bOff,int4 bSize,bool bigEndian) {
byteOffset = bOff; byteSize = bSize; leastSigBit = 0; numBits = bSize * 8; isBigEndian = bigEndian; } ///< Construct byte range
BitRange(const BitRange &op2,int4 off,int4 sz); ///< Constructor, copy range into new container
BitRange(int4 bOff,int4 bSize,int4 least,int4 num,bool bigEndian) { byteOffset = bOff; byteSize = bSize; leastSigBit = least;
numBits = num; isBigEndian = bigEndian; } ///< Constructor
bool empty(void) const { return (numBits <= 0); } ///< Return \b true if \b this is an empty bit range (zero bits)
int4 compare(const BitRange &op2) const; ///< Compare \b this with another as containers
int4 translateLSB(const BitRange &op2) const; ///< Translate the \b leastSigBit of the given range into \b this reference frame
int4 overlapTest(const BitRange &op2) const; ///< Characterize the type of overlap between \b this and another range
void intersection(const BitRange &op2); ///< Replace \b this with the intersection of \b this with another BitRange
void intersectMask(uintb mask); ///< Restrict \b this with a mask that lines up with the container
void shift(int4 leftShiftAmount); ///< Replace \b this with the shifted range
void truncateMostSigBytes(int4 num); ///< Truncate the most significant bytes in the byte container
void truncateLeastSigBytes(int4 num); ///< Truncate the least significant bytes in the byte container
void extendBytes(int4 num); ///< Add most significant bytes to the container
uintb getMask(void) const; ///< Get mask representing \b this range
bool isByteRange(void) const; ///< Return \b true if \b this bit range is also a byte range
bool isMostSignificant(void) const; ///< Return \b true if the bit range occupies the most significant bits of the container
void minimizeContainer(void); ///< Shrink the container to fit the bit range
void expandToMost(void); ///< Expand the bitrange until it includes the most significant bits of the container
};
/// Precalculated masks indexed by size
extern uintb uintbmasks[];
@@ -577,6 +608,7 @@ extern bool signbit_negative(uintb val,int4 size); ///< Return true if the sign-
extern uintb calc_mask(int4 size); ///< Calculate a mask for a given byte size
extern uintb uintb_negate(uintb in,int4 size); ///< Negate the \e sized value
extern uintb sign_extend(uintb in,int4 sizein,int4 sizeout); ///< Sign-extend a value between two byte sizes
extern uintb extend_signbit(uintb val,int4 numbits,int4 size); ///< Extend a signed value of given number of bits to a full integer
extern void byte_swap(intb &val,int4 size); ///< Swap bytes in the given value
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,266 @@
/* ###
* 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.
*/
/// \file bitfield.hh
/// \brief Classes for transforming bitfield expressions
#ifndef __BITFIELD_HH__
#define __BITFIELD_HH__
#include "ruleaction.hh"
namespace ghidra {
/// \brief Description of the bitfields covered by a Varnode
class BitFieldNodeState {
public:
BitRange bitsUsed; ///< Bits being used from \b this Varnode
BitRange bitsField; ///< Bits from bit-field being followed
Varnode *node; ///< Varnode holding bitfields
const TypeBitField *field; ///< Bit-field being followed
int4 origLeastSigBit; ///< Original position of least significant bit
bool isSignExtended; ///< Bitfield has been sign-extended into node
BitFieldNodeState(const BitRange &used,Varnode *vn,const TypeBitField *fld); ///< Constructor to follow a field
BitFieldNodeState(const BitRange &used,Varnode *vn,int4 leastSig,int4 numBits); ///< Constructor for a hole
BitFieldNodeState(const BitFieldNodeState &copy,const BitRange &newField,Varnode *vn,bool sgnExt); ///< Copy constructor with new \b bitsField
/// \brief Can the current Varnode be treated as the isolated bitfield
bool isFieldAligned(void) const { return (bitsField.leastSigBit == 0 && bitsField.numBits == bitsUsed.numBits); }
/// \brief Return \b true if the signedness of the field matches the extension used to extract it
bool doesSignExtensionMatch(void) const { return isSignExtended == (field->type->getMetatype() == TYPE_INT); }
};
/// \brief Class for transforming bitfield expressions
///
/// For both insertion and extraction, establish the bitfields that need to be traced.
class BitFieldTransform {
protected:
Funcdata *func; ///< The containing function
TypeStruct *parentStruct; ///< Structure owning the bitfields
list<BitFieldNodeState> workList; ///< Fields that are being followed
int4 initialOffset; ///< Byte offset into parent structure
int4 containerSize; ///< Size of Varnode containing bitfields
bool isBigEndian; ///< Endianness associated with bitfields
void establishFields(Varnode *vn,bool followHoles); ///< Build worklist for each bitfield overlapped by given Varnode
Datatype *buildPartialType(void); ///< Build the (partial) data-type associated with the root bitfield container
static bool findOverwrite(Varnode *vn,BlockBasic *bl,const BitRange &range);
public:
BitFieldTransform(Funcdata *f,Datatype *dt,int4 off); ///< Constructor setting up basic info about bitfield data-type
};
/// \brief Class that converts bitfield insertion expressions into explicit INSERT operations
///
/// The doTrace() method traces backward from a root Varnode that contains bitfields to find points that
/// can be treated as a value written to an individual bitfield, creating an InsertRecord at each point.
/// If all bits of the Varnode are accounted for, the apply() method transforms expressions based on any InsertRecord.
class BitFieldInsertTransform : public BitFieldTransform {
/// \brief Info about a Varnode that can be treated as a write to a single bitfield
class InsertRecord {
friend class BitFieldInsertTransform;
Varnode *vn; ///< Value being inserted (or null)
uintb constVal; ///< Constant value being inserted
Datatype *dt; ///< Data-type associated with value
int4 pos; ///< Position being inserted to
int4 numBits; ///< Number of bits being inserted
int4 shiftAmount; ///< Amount that value needs to be right shifted
public:
InsertRecord(Varnode *v,Datatype *d,int4 p,int4 sz,int4 sa) { vn = v; dt = d; constVal = 0; pos = p; numBits = sz; shiftAmount = sa; } ///< Constructor for Varnode
InsertRecord(uintb val,Datatype *d,int4 p,int4 sz) { vn = (Varnode *)0; dt = d; constVal = val; pos = p; numBits = sz; shiftAmount = 0; } ///< Constructor for constant
};
PcodeOp *finalWriteOp; ///< STORE to bitfields or op outputing to bitfields
Varnode *originalValue; ///< Value prior to insertion
Varnode *mappedVn; ///< Bitfield container written to
list<InsertRecord> insertList; ///< Insertion actions
bool verifyLoadStoreOriginalValue(uintb mask) const; ///< Test for other STORE ops interfering with the \e original \e value
bool verifyMappedOriginalValue(uintb mask) const; ///< Test for other ops interfering with the mapped \e original \e value
uintb constructOriginalValueMask(void) const; ///< Calculate mask where 1 bits represent all the bits being preserved
bool verifyOriginalValueBits(void) const; ///< Do final check that unINSERTed bits come from the \e original \e value
bool isOverwrittenPartial(const BitFieldNodeState &state); ///< Is given state a partial field that is overwritten later
bool checkPulledOriginalValue(BitFieldNodeState &state); ///< Is this an original value defined by ZPULL or SPULL
bool checkOriginalBase(Varnode *vn); ///< Check if the given Varnode is the original LOAD or mapped value
bool isOriginalValue(BitFieldNodeState &state); ///< Is the given Varnode a (partial) copy of the original value being INSERTed into
bool addConstantWrite(BitFieldNodeState &state); ///< Create InsertRecord writing a constant into the field
bool addZeroOut(BitFieldNodeState &state); ///< Create InsertRecord writing 0 into the field
void addFieldWrite(BitFieldNodeState &state); ///< Create InsertRecord writing Varnode into the field
bool handleAndBack(BitFieldNodeState &state,PcodeOp *op); ///< Follow bitfield back through INT_AND with a mask
bool handleOrBack(BitFieldNodeState &state,PcodeOp *op); ///< Follow bitfield back through one branch of INT_OR
bool handleAddBack(BitFieldNodeState &state,PcodeOp *op); ///< Follow bitfield back through one branch of INT_AND
bool handleLeftBack(BitFieldNodeState &state,PcodeOp *op); ///< Follow bitfield back through INT_LEFT by a constant
bool handleRightBack(BitFieldNodeState &state,PcodeOp *op); ///< Follow bitfield back through INT_SRIGHT by a constant
bool handleZextBack(BitFieldNodeState &state,PcodeOp *op); ///< Follow bitfield back through INT_ZEXT
bool handleMultBack(BitFieldNodeState &state,PcodeOp *op); ///< Follow bitfield back through INT_MULT
bool handleSubpieceBack(BitFieldNodeState &state,PcodeOp *op); ///< Follow bitfield back through SUBPIECE
bool testCallOriginal(BitFieldNodeState &state,PcodeOp *op); ///< Test if a call is producing the \e original \e value
bool processBackward(BitFieldNodeState &state); ///< Follow field back, creating an InsertRecord if possible
PcodeOp *setInsertInputs(PcodeOp *op,const InsertRecord &rec); ///< Fill-in INSERT inputs based on given InsertRecord
void addFieldShift(PcodeOp *insertOp,const InsertRecord &rec); ///< Create any shift p-code op specified by given InsertRecord
bool foldLoad(PcodeOp *loadOp) const; ///< Try to mark LOAD as part of INSERT
void foldPtrsub(PcodeOp *loadOp) const; ///< Try to mark PTRSUB as part of INSERT
void checkRedundancy(const InsertRecord &rec); ///< Check if value is getting INSERTed twice and remove second
public:
BitFieldInsertTransform(Funcdata *f,PcodeOp *op,Datatype *dt,int4 off); ///< Construct from a terminating op
bool doTrace(void); ///< Trace bitfields backward from the terminating op
void apply(void); ///< Transform recovered expressions into INSERT operations
};
/// \brief Class that converts bitfield pull expressions into explicit ZPULL and SPULL operations
///
/// The doTrace() method traces forward from a root Varnode that contains bitfields to find points where
/// an individual bitfield has been fully isolated, creating an PullRecord at each point.
/// If all bits of the Varnode are accounted for, the apply() method transforms expressions based on any PullRecord.
class BitFieldPullTransform : public BitFieldTransform {
/// \brief During final transformation, this is the state maintained between processing individual PullRecords
class TransformState {
friend class BitFieldPullTransform;
vector<PcodeOp *> deadScratch; ///< Scratch space for opDestroyRecursive method
Datatype *partialType; ///< Partial data-type of the root container
int4 count; ///< Number of PullRecords processed
};
/// \brief Info about a single read by a PcodeOp that can be treated as a \e pull of 1 or more bitfields
class PullRecord {
enum {
normal = 0, ///< A single field pull
equal = 1, ///< Pull for INT_EQUAL or INT_NOTEQUAL
aborted = 2 ///< Code to indicate that the pull for the entire PcodeOp should be aborted
};
friend class BitFieldPullTransform;
Varnode *readVn; ///< Varnode holding pulled value
PcodeOp *readOp; ///< Op reading the pulled value, or null if readVn itself is redefined
Datatype *dt; ///< Data-type associated with the pulled value
int4 type; ///< Type of pull
int4 pos; ///< Bit position of field being pulled
int4 numBits; ///< Number of bits in field being pulled
int4 leftShift; ///< Amount final field is left shifted
uintb mask; ///< Mask representing the bitfield within the Varnode
public:
PullRecord(const BitFieldNodeState &state,PcodeOp *op); ///< Construct pull record for a specific PcodeOp read
PullRecord(const BitFieldNodeState &state,PcodeOp *op,uintb val); ///< Construct record for a pull into an INT_EQUAL or INT_NOTEQUAL
PullRecord(PcodeOp *op); ///< Construct record representing an abort
bool operator<(const PullRecord &op2) const; ///< Compare records
};
Varnode *root; ///< Value being pulled from
PcodeOp *loadOp; ///< LOAD op producing root (if non-null)
list<PullRecord> pullList; ///< Pull actions
static bool testConsumed(Varnode *vn,const BitRange &bitField); ///< Test if all consumed bits are in the given bitfield
void handleLeftForward(const BitFieldNodeState &state,PcodeOp *op); ///< Follow bitfield forward through INT_LEFT
void handleRightForward(const BitFieldNodeState &state,PcodeOp *op); ///< Follow bitfield forward through INT_RIGHT
void handleAndForward(const BitFieldNodeState &state,PcodeOp *op); ///< Follow bitfield forward through INT_AND
void handleExtForward(const BitFieldNodeState &state,PcodeOp *op); ///< Follow bitfield forward through INT_ZEXT
void handleMultForward(const BitFieldNodeState &state,PcodeOp *op); ///< Follow bitfield forward through INT_MULT
void handleSubpieceForward(const BitFieldNodeState &state,PcodeOp *op); ///< Follow bitfield forward through SUBPIECE
void handleInsertForward(const BitFieldNodeState &state,PcodeOp *op); ///< Follow bitfield forward into INSERT
void handleLessForward(const BitFieldNodeState &state,PcodeOp *op); ///< Follow bitfield forward through INT_LESS, INT_SLESS
void handleLeastSigOp(const BitFieldNodeState &state,PcodeOp *op); ///< Follow bitfield into INT_ADD, INT_MULT, INT_OR, INT_XOR
void handleEqualForward(const BitFieldNodeState &state,PcodeOp *op); ///< Follow bitfield into INT_EQUAL or INT_NOTEQUAL
void processForward(BitFieldNodeState &state); ///< Follow bitfield forward one level through all its descendants
list<PullRecord>::iterator testCompareGroup(list<PullRecord>::iterator iter);
void applyRecord(PullRecord &rec,TransformState &state); ///< Perform transform corresponding to the given PullRecord
void applyCompareRecord(const PullRecord &rec); ///< Perform transform on an INT_EQUAL or INT_NOTEQUAL
bool foldLoad(PcodeOp *loadOp) const; ///< Try to mark LOAD as part of ZPULL or SPULL
void foldPtrsub(PcodeOp *loadOp) const; ///< Try to mark PTRSUB as part of ZPULL or SPULL
public:
BitFieldPullTransform(Funcdata *f,Varnode *r,Datatype *dt,int4 off); ///< Construct from Varnode containing bitfields
bool doTrace(void); ///< Trace bitfields from \b root to points where they are pulled
void apply(void); ///< Transform recovered expressions into ZPULL or SPULL operations
};
/// \brief Collapse bitfield insertion ending in a CPUI_STORE
class RuleBitFieldStore : public Rule {
public:
RuleBitFieldStore(const string &g) : Rule( g, 0, "bitfield_store") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RuleBitFieldStore(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
/// \brief Collapse bitfield insertion ending in a write to a mapped Varnode
class RuleBitFieldOut : public Rule {
public:
RuleBitFieldOut(const string &g) : Rule( g, 0, "bitfield_out") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RuleBitFieldOut(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
/// \brief Collapse bitfield pulls starting with a CPUI_LOAD
class RuleBitFieldLoad : public Rule {
public:
RuleBitFieldLoad(const string &g) : Rule( g, 0, "bitfield_load") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RuleBitFieldLoad(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
/// \brief Collapse bitfield pulls starting with mapped Varnodes
class RuleBitFieldIn : public Rule {
public:
RuleBitFieldIn(const string &g) : Rule( g, 0, "bitfield_in") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RuleBitFieldIn(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
/// \brief Simplify expressions explicitly using ZPULL and SPULL p-code ops
class RulePullAbsorb : public Rule {
int4 absorbRight(Funcdata &data,PcodeOp *rightOp,PcodeOp *pullOp);
int4 absorbRightAndCompZero(Funcdata &data,PcodeOp *rightOp,PcodeOp *andOp,PcodeOp *pullOp);
int4 absorbLeft(Funcdata &data,PcodeOp *leftOp,PcodeOp *pullOp);
int4 absorbLeftRight(Funcdata &data,PcodeOp *rightOp,PcodeOp *leftOp,PcodeOp *pullOp);
int4 absorbLeftAnd(Funcdata &data,PcodeOp *andOp,PcodeOp *leftOp,PcodeOp *pullOp);
int4 absorbAnd(Funcdata &data,PcodeOp *andOp,PcodeOp *pullOp);
int4 absorbCompare(Funcdata &data,PcodeOp *compOp,PcodeOp *leftOp,PcodeOp *pullOp);
int4 absorbExt(Funcdata &data,PcodeOp *extOp,PcodeOp *pullOp);
int4 absorbSubpiece(Funcdata &data,PcodeOp *subOp,PcodeOp *pullOp);
int4 absorbCompZero(Funcdata &data,PcodeOp *compOp,PcodeOp *pullOp);
public:
RulePullAbsorb(const string &g) : Rule( g, 0, "pull_absorb") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RulePullAbsorb(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
/// \brief Simplify expressions explicitly using the INSERT p-code op
class RuleInsertAbsorb : public Rule {
static Varnode *leftShiftVarnode(Varnode *vn,int4 sa); ///< Test if a Varnode is left-shifted by the given amount
int4 absorbAnd(Funcdata &data,PcodeOp *andOp,PcodeOp *insertOp);
int4 absorbRightLeft(Funcdata &data,PcodeOp *nextOp,PcodeOp *rightOp,PcodeOp *insertOp);
int4 absorbShiftAdd(Funcdata &data,PcodeOp *rightOp,PcodeOp *addOp,PcodeOp *insertOp);
int4 absorbNestedAnd(Funcdata &data,PcodeOp *baseOp,PcodeOp *insertOp);
public:
RuleInsertAbsorb(const string &g) : Rule( g, 0, "insert_absorb") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RuleInsertAbsorb(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
} // End namespace ghidra
#endif
@@ -507,7 +507,7 @@ void HeapSequence::findDuplicateBases(vector<Varnode *> &duplist)
if (!copyRoot->isWritten()) break;
op = copyRoot->getDef();
opc = op->code();
if (opc != CPUI_PTRSUB && opc != CPUI_INT_ADD && opc != CPUI_PTRSUB)
if (opc != CPUI_PTRSUB && opc != CPUI_INT_ADD && opc != CPUI_PTRADD)
break;
} while(op->getIn(1)->isConstant());
@@ -523,7 +523,7 @@ void HeapSequence::findDuplicateBases(vector<Varnode *> &duplist)
op = *iter;
++iter;
opc = op->code();
if (opc != CPUI_PTRSUB && opc != CPUI_INT_ADD && opc != CPUI_PTRSUB)
if (opc != CPUI_PTRSUB && opc != CPUI_INT_ADD && opc != CPUI_PTRADD)
continue;
if (op->getIn(0) != vn || !op->getIn(1)->isConstant())
continue;
@@ -18,6 +18,7 @@
#include "double.hh"
#include "subflow.hh"
#include "constseq.hh"
#include "bitfield.hh"
namespace ghidra {
@@ -1540,7 +1541,7 @@ void ActionFuncLink::funcLinkOutput(FuncCallSpecs *fc,Funcdata &data)
Datatype *outtype = outparam->getType();
if (outtype->getMetatype() != TYPE_VOID) {
int4 sz = outparam->getSize();
if (sz == 1 && outtype->getMetatype() == TYPE_BOOL && data.isTypeRecoveryOn())
if (outtype->getMetatype() == TYPE_BOOL && data.isTypeRecoveryOn())
data.opMarkCalculatedBool(callop);
Address addr = outparam->getAddress();
if (addr.getSpace()->getType() == IPTR_SPACEBASE) {
@@ -2349,6 +2350,7 @@ int4 ActionDefaultParams::apply(Funcdata &data)
void ActionSetCasts::checkPointerIssues(PcodeOp *op,Varnode *vn,Funcdata &data)
{
if (op->doesSpecialPrinting()) return;
Datatype *ptrtype = op->getIn(1)->getHighTypeReadFacing(op);
int4 valsize = vn->getSize();
if ((ptrtype->getMetatype()!=TYPE_PTR)|| (((TypePointer *)ptrtype)->getPtrTo()->getSize() != valsize)) {
@@ -3062,6 +3064,11 @@ int4 ActionMarkExplicit::baseExplicit(Varnode *vn,int4 maxref)
return -1;
}
if (vn->hasNoDescend()) return -1; // Must have at least one descendant
if (def->code() == CPUI_INSERT) {
PcodeOp *storeOp = def->getOut()->loneDescend();
if (storeOp == (PcodeOp *)0 || storeOp->code() != CPUI_STORE)
return -1; // INSERT output is explicit unless it is immediately used by STORE
}
if (def->code() == CPUI_PTRSUB) { // A dereference
Varnode *basevn = def->getIn(0);
@@ -3703,6 +3710,9 @@ void ActionDeadCode::propagateConsumed(vector<Varnode *> &worklist)
if (sz > sizeof(uintb)) { // If there exists bits beyond the precision of the consume field
if (sa >= 8*sizeof(uintb))
a = ~((uintb)0); // Make sure we assume one bits where we shift in unrepresented bits
else if (sa == 0) {
a = outc;
}
else
a = (outc >> sa) ^ ( (~((uintb)0)) << (8*sizeof(uintb)-sa));
sz = 8*sz -sa;
@@ -3763,10 +3773,11 @@ void ActionDeadCode::propagateConsumed(vector<Varnode *> &worklist)
pushConsumed(b,op->getIn(2), worklist);
pushConsumed(b,op->getIn(3), worklist);
break;
case CPUI_EXTRACT:
case CPUI_ZPULL:
case CPUI_SPULL:
a = 1;
a <<= (int4)op->getIn(2)->getOffset();
a -= 1; // Extract mask
a -= 1; // Pull mask
a &= outc; // Consumed bits of mask
a <<= (int4)op->getIn(1)->getOffset();
pushConsumed(a,op->getIn(0),worklist);
@@ -5425,7 +5436,7 @@ void ActionDatabase::buildDefaultGroups(void)
"deadcode", "typerecovery", "stackptrflow",
"blockrecovery", "stackvars", "deadcontrolflow", "switchnorm",
"cleanup", "splitcopy", "splitpointer", "merge", "dynamic", "casts", "analysis",
"fixateglobals", "fixateproto", "constsequence",
"fixateglobals", "fixateproto", "constsequence", "bitfields",
"segment", "returnsplit", "nodejoin", "doubleload", "doubleprecis",
"unreachable", "subvar", "floatprecision",
"conditionalexe", "" };
@@ -5708,6 +5719,12 @@ void ActionDatabase::universalAction(Architecture *conf)
actcleanup->addRule( new RuleSplitStore("splitpointer") );
actcleanup->addRule( new RuleStringCopy("constsequence"));
actcleanup->addRule( new RuleStringStore("constsequence"));
actcleanup->addRule( new RuleBitFieldStore("bitfields"));
actcleanup->addRule( new RuleBitFieldOut("bitfields"));
actcleanup->addRule( new RuleBitFieldLoad("bitfields"));
actcleanup->addRule( new RuleBitFieldIn("bitfields"));
actcleanup->addRule( new RulePullAbsorb("bitfields"));
actcleanup->addRule( new RuleInsertAbsorb("bitfields"));
}
act->addAction( actcleanup );
@@ -4,9 +4,9 @@
* 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.
@@ -57,8 +57,8 @@ const 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_INSERT, CPUI_EXTRACT,
CPUI_POPCOUNT, CPUI_LZCOUNT
CPUI_SEGMENTOP, CPUI_CPOOLREF, CPUI_NEW, CPUI_INSERT, CPUI_ZPULL,
CPUI_POPCOUNT, CPUI_LZCOUNT, CPUI_SPULL
};
@@ -14,6 +14,7 @@
* limitations under the License.
*/
#include "expression.hh"
#include "database.hh"
namespace ghidra {
@@ -392,6 +393,198 @@ void AddExpression::gatherTwoTermsRoot(Varnode *root)
gather(root,(uintb)1,1);
}
/// Find the structure immediately containing the byte range described by the given data-type.
/// Then, given the least significant bit of the bitfield, find the structure immediately containing the bitfield,
/// which may be a different structure.
/// \param dt is the data-type describing the byte range
/// \param initByteOff is the initial offset of the byte range within the data-type (may be -1)
/// \param leastBitOff is the least significant bit of the bitfield within the byte range
/// \param isBigEndian is \b true if the data-type is stored in big endian memory
void BitFieldExpression::getStructures(Datatype *dt,int4 initByteOff,int4 leastBitOff,bool isBigEndian)
{
TypeStruct *encompassStruct;
theStruct = (TypeStruct *)0;
byteRangeOffset = (initByteOff < 0) ? 0 : initByteOff;
if (dt->getMetatype() == TYPE_PARTIALSTRUCT) {
TypePartialStruct *partial = (TypePartialStruct *)dt;
Datatype *structTmp = partial->getParent();
if (structTmp->getMetatype() != TYPE_STRUCT) return;
byteRangeOffset += partial->getOffset();
encompassStruct = (TypeStruct *)structTmp;
}
else if (dt->getMetatype() == TYPE_STRUCT) {
encompassStruct = (TypeStruct *)dt;
}
else
return;
int8 offset = byteRangeOffset;
leastBitOff /= 8;
if (isBigEndian)
offset += (dt->getSize() - leastBitOff - 1);
else
offset += leastBitOff;
theStruct = encompassStruct;
offsetToBitStruct = 0;
for(;;) {
int8 newoff;
Datatype *tmpDt = theStruct->getSubType(offset, &newoff);
if (tmpDt == (Datatype *)0) break;
if (tmpDt->getMetatype() != TYPE_STRUCT) break;
theStruct = (TypeStruct *)tmpDt;
offsetToBitStruct += (offset-newoff);
offset = newoff;
}
}
const Varnode *BitFieldExpression::recoverStructurePointer(const Varnode *vn,int4 offset)
{
if (offset == 0 && theStruct->getSize() == vn->getSize())
return vn;
else if (vn->isWritten()) {
const PcodeOp *ptrSub = vn->getDef();
if (ptrSub->code() == CPUI_PTRSUB) {
if ((int4)ptrSub->getIn(1)->getOffset() == offset) {
return ptrSub->getIn(0);
}
}
}
if (offset != 0)
return (const Varnode *)0;
return vn;
}
/// \param pull is the given ZPULL or SPULL
/// \return the corresponding bitfield description or null
const TypeBitField *BitFieldExpression::getPullField(const PcodeOp *pull)
{
BitFieldExpression expr;
const Varnode *inVn = pull->getIn(0);
int4 leastBitOff = (int4)pull->getIn(1)->getOffset();
int4 bitSize = (int4)pull->getIn(2)->getOffset();
bool isBig = inVn->getSpace()->isBigEndian();
Datatype *dt = inVn->getTypeReadFacing(pull);
expr.getStructures(dt, 0, leastBitOff, isBig);
if (expr.theStruct == (TypeStruct *)0)
return (const TypeBitField *)0;
BitRange range(expr.byteRangeOffset-expr.offsetToBitStruct,inVn->getSize(),leastBitOff,bitSize,isBig);
return expr.theStruct->findMatchingBitField(range);
}
InsertExpression::InsertExpression(const PcodeOp *insert)
{
insertOp = insert;
bitfield = (const TypeBitField *)0;
const Varnode *value = insertOp->getOut();
symbol = value->getHigh()->getSymbol();
if (symbol == (const Symbol *)0) return;
AddrSpace *spc = value->getSpace();
int4 leastBitOff = (int4)insertOp->getIn(2)->getOffset();
int4 bitSize = (int4)insertOp->getIn(3)->getOffset();
getStructures(symbol->getType(),value->getHigh()->getSymbolOffset(),leastBitOff,spc->isBigEndian());
if (theStruct == (TypeStruct *)0) return;
BitRange range(byteRangeOffset - offsetToBitStruct,value->getSize(),leastBitOff,bitSize,spc->isBigEndian());
bitfield = theStruct->findMatchingBitField(range);
}
/// \param insert is the CPUI_INSERT op
/// \return a mask with a 1 wherever bits are inserted by the op
uintb InsertExpression::getRangeMask(const PcodeOp *insert)
{
int4 leastBitOff = (int4)insert->getIn(2)->getOffset();
int4 bitSize = (int4)insert->getIn(3)->getOffset();
uintb res = 0;
res = ~res;
if (bitSize < 8 * sizeof(uintb))
res = ~(res << bitSize);
res <<= leastBitOff;
return res;
}
/// \param insert is the CPUI_INSERT op
/// \return mask with of the least significant bits
uintb InsertExpression::getLSBMask(const PcodeOp *insert)
{
int4 bitSize = (int4)insert->getIn(3)->getOffset();
uintb res = 0;
res = ~res;
if (bitSize < 8 * sizeof(uintb))
res = ~(res << bitSize);
return res;
}
InsertStoreExpression::InsertStoreExpression(const PcodeOp *store)
{
bitfield = (const TypeBitField *)0;
structPtr = (Varnode *)0;
theStruct = (TypeStruct *)0;
loadOp = (PcodeOp *)0;
const Varnode *value = store->getIn(2);
if (!value->isWritten()) return;
insertOp = value->getDef();
if (insertOp->code() != CPUI_INSERT) return;
const Varnode *dest = insertOp->getIn(0); // dest can either be a constant or LOAD
if (dest->isWritten()) {
loadOp = dest->getDef();
if (loadOp->code() != CPUI_LOAD) return;
}
else if (!dest->isConstant())
return;
AddrSpace *spc = store->getIn(0)->getSpaceFromConst();
int4 leastBitOff = (int4)insertOp->getIn(2)->getOffset();
int4 bitSize = (int4)insertOp->getIn(3)->getOffset();
getStructures(value->getTypeDefFacing(),0,leastBitOff,spc->isBigEndian());
if (theStruct == (TypeStruct *)0) return;
structPtr = recoverStructurePointer(store->getIn(1), byteRangeOffset);
if (structPtr == (const Varnode *)0) return;
BitRange range(byteRangeOffset - offsetToBitStruct,value->getSize(),leastBitOff,bitSize,spc->isBigEndian());
bitfield = theStruct->findMatchingBitField(range);
}
PullExpression::PullExpression(const PcodeOp *pull)
{
pullOp = pull;
bitfield = (const TypeBitField *)0;
theStruct = (TypeStruct *)0;
loadOp = (const PcodeOp *)0;
structPtr = (const Varnode *)0;
const Varnode *inVn = pullOp->getIn(0);
AddrSpace *spc;
Datatype *dt;
int4 offset;
if (inVn->isWritten() && inVn->getDef()->code() == CPUI_LOAD) {
loadOp = inVn->getDef();
spc = loadOp->getIn(0)->getSpaceFromConst();
dt = inVn->getTypeReadFacing(pullOp);
offset = 0;
}
else {
symbol = inVn->getHigh()->getSymbol();
if (symbol == (const Symbol *)0) return;
spc = inVn->getSpace();
dt = symbol->getType();
offset = inVn->getHigh()->getSymbolOffset();
}
int4 leastBitOff = (int4)pullOp->getIn(1)->getOffset();
int4 bitSize = (int4)pullOp->getIn(2)->getOffset();
getStructures(dt,offset,leastBitOff,spc->isBigEndian());
if (theStruct == (TypeStruct *)0) return;
if (loadOp != (const PcodeOp *)0) {
structPtr = recoverStructurePointer(loadOp->getIn(1), byteRangeOffset);
if (structPtr == (const Varnode *)0) return;
}
BitRange range(byteRangeOffset-offsetToBitStruct,inVn->getSize(),leastBitOff,bitSize,spc->isBigEndian());
bitfield = theStruct->findMatchingBitField(range);
}
/// \brief Perform basic comparison of two given Varnodes
///
/// Return
@@ -559,4 +752,53 @@ bool functionalDifference(Varnode *vn1,Varnode *vn2,int4 depth)
return false;
}
/// \brief Back-track as far as possible from a pointer Varnode thru PTRSUB, INT_ADD, and COPY collecting offsets
///
/// The pointer that is reached by back-tracking is returned, and any accumulated offset is passed back.
/// \param vn is the pointer Varnode
/// \param offset passes back the accumulated offset
/// \return the reached Varnode pointer
Varnode *rootPointer(Varnode *vn,uintb &offset)
{
offset = 0;
for(;;) {
if (!vn->isWritten()) break;
PcodeOp *op = vn->getDef();
OpCode opc = op->code();
if (opc == CPUI_PTRSUB) {
offset += op->getIn(1)->getOffset();
vn = op->getIn(0);
}
else if (opc == CPUI_INT_ADD) {
Varnode *cvn = op->getIn(1);
if (!cvn->isConstant()) break;
offset += cvn->getOffset();
vn = op->getIn(0);
}
else if (opc == CPUI_COPY) {
vn = op->getIn(0);
}
else
break;
}
return vn;
}
/// \brief Determine if two pointer Varnodes always hold the same value
///
/// \param vn1 is the first pointer to compare
/// \param vn2 is the second pointer to compare
bool pointerEquality(Varnode *vn1,Varnode *vn2)
{
uintb off1,off2;
if (vn1 == vn2) return true;
vn1 = rootPointer(vn1,off1);
vn2 = rootPointer(vn2,off2);
if (off1 != off2) return false;
return (vn1 == vn2);
}
} // End namespace ghidra
@@ -134,6 +134,17 @@ public:
const vector<AdditiveEdge *> &getSort(void) { return sorter; } ///< Get the sorted list of references
};
/// \brief A comparison operator for ordering terms in a sum
///
/// This is based on Varnode::termOrder which groups constants terms and
/// ignores multiplicative coefficients.
/// \param op1 is the first term to compare
/// \param op2 is the second term
/// \return \b true if the first term is less than the second
inline bool TermOrder::additiveCompare(const AdditiveEdge *op1,const AdditiveEdge *op2) {
return (-1 == op1->getVarnode()->termOrder(op2->getVarnode()));
}
/// \brief Class for lightweight matching of two additive expressions
///
/// Collect (up to 2) terms along with any constants and coefficients.
@@ -161,20 +172,67 @@ public:
bool isEquivalent(const AddExpression &op2) const; ///< Determine if 2 expressions are equivalent
};
/// \brief A comparison operator for ordering terms in a sum
/// \brief A container for an expression manipulating a bitfield
///
/// This is based on Varnode::termOrder which groups constants terms and
/// ignores multiplicative coefficients.
/// \param op1 is the first term to compare
/// \param op2 is the second term
/// \return \b true if the first term is less than the second
inline bool TermOrder::additiveCompare(const AdditiveEdge *op1,const AdditiveEdge *op2) {
return (-1 == op1->getVarnode()->termOrder(op2->getVarnode()));
}
/// The expression centers around either a CPUI_INSERT or a CPUI_EXTRACT op but encompasses multiple p-code ops
/// that represent either a single read of or single write to a bitfield within a structure. This class recovers
/// the expected elements of the expression. The method isValid() returns \b true if the expression has the
/// expected form and can be interpreted as a single read or write.
class BitFieldExpression {
protected:
void getStructures(Datatype *dt,int4 initByteOff,int4 leastBitOff,bool isBigEndian); ///< Recover the structure(s) holding the bitfield
public:
TypeStruct *theStruct; ///< Parent structure containing the bitfield
const TypeBitField *bitfield; ///< Formal bitfield description
int4 byteRangeOffset; ///< Offset of byte range into encompassStruct
int4 offsetToBitStruct; ///< Offset of structure containing bitfield in encompassStruct
const Varnode *recoverStructurePointer(const Varnode *vn,int4 offset); ///< Recover the Varnode holding the pointer to the parent structure
bool isValid(void) const { return (bitfield != (const TypeBitField *)0); } ///< Is \b this a valid bitfield expression
static const TypeBitField *getPullField(const PcodeOp *pull); ///< Get field description corresponding to given ZPULL or SPULL
};
/// \brief A write to a bitfield stored in an explicit Varnode
///
/// The INSERT output is expected to be a associated with a (partial) symbol and
/// hold data-type information.
class InsertExpression : public BitFieldExpression {
public:
const PcodeOp *insertOp; ///< INSERT op
const Symbol *symbol; ///< Structure symbol represented by the INSERT output
InsertExpression(const PcodeOp *insert); ///< Construct from an INSERT
static uintb getRangeMask(const PcodeOp *insert); ///< Get a mask representing the INSERTed range of bits
static uintb getLSBMask(const PcodeOp *insert); ///< Get mask of least significant bits matching INSERT size
};
/// \brief A write to a bitfield through a STORE op
///
/// The INSERT output is expected to hold data-type info. A final STORE must be
/// present and a LOAD, recovering parts of the structure that are unaffected, may be present.
class InsertStoreExpression : public BitFieldExpression {
public:
const PcodeOp *insertOp; ///< INSERT op
const PcodeOp *loadOp; ///< LOAD op (may be null)
const Varnode *structPtr; ///< Varnode holding pointer to the parent structure
InsertStoreExpression(const PcodeOp *store); ///< Construct from a STORE
};
/// \brief A read of a bitfield via a ZPULL or SPULL operator
///
/// The first input to the operator must either be a (partial) symbol or be written by a LOAD.
class PullExpression : public BitFieldExpression {
public:
const PcodeOp *pullOp; ///< ZPULL or SPULL op
const Symbol *symbol; ///< Symbol holding the structure and bitfield (may be null)
const PcodeOp *loadOp; ///< LOAD reading bytes containing the bitfield (may be null)
const Varnode *structPtr; ///< Varnode holding pointer to the parent structure
PullExpression(const PcodeOp *pull); ///< Construct from a ZPULL or SPULL
};
extern int4 functionalEqualityLevel(Varnode *vn1,Varnode *vn2,Varnode **res1,Varnode **res2);
extern bool functionalEquality(Varnode *vn1,Varnode *vn2);
extern bool functionalDifference(Varnode *vn1,Varnode *vn2,int4 depth);
extern Varnode *rootPointer(Varnode *vn,uintb &offset);
extern bool pointerEquality(Varnode *vn1,Varnode *vn2);
} // End namespace ghidra
#endif
@@ -292,6 +292,7 @@ public:
Varnode *newExtendedConstant(int4 s,uint8 *val,PcodeOp *op); ///< Create extended precision constant
void adjustInputVarnodes(const Address &addr,int4 sz);
void deleteVarnode(Varnode *vn) { vbank.destroy(vn); } ///< Delete the given varnode
void destroyVarnodeRecursive(Varnode *vn); ///< Destroy Varnode (if unused) and any PcodeOp that produced it
Address findDisjointCover(Varnode *vn,int4 &sz); ///< Find range covering given Varnode and any intersecting Varnodes
@@ -536,6 +536,22 @@ void Funcdata::adjustInputVarnodes(const Address &addr,int4 sz)
}
}
/// If the Varnode has descendants or is address forced, this method does nothing.
/// Otherwise, the Varnode is destroyed as is its defining PcodeOp. Any dead inputs to the PcodeOp are
/// then destroyed recursively.
/// \param vn is the Varnode to destroy
void Funcdata::destroyVarnodeRecursive(Varnode *vn)
{
if (vn->isAutoLive() || !vn->hasNoDescend()) return;
if (!vn->isWritten()) {
vbank.destroy(vn);
return;
}
vector<PcodeOp *> scratch;
opDestroyRecursive(vn->getDef(), scratch);
}
/// All p-code ops that read the Varnode are transformed so that they read
/// a special constant instead (associate with unreachable block removal).
/// \param vn is the given Varnode
@@ -888,6 +904,9 @@ void Funcdata::calcNZMask(void)
if (!vn->isWritten()) {
if (vn->isConstant())
vn->nzm = vn->getOffset();
else if (vn->isTypeLock() && vn->getType()->getMetatype() == TYPE_BOOL) {
vn->nzm = 1;
}
else {
vn->nzm = calc_mask(vn->getSize());
if (vn->isSpacebase())
File diff suppressed because it is too large Load Diff
@@ -4,9 +4,9 @@
* 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.
@@ -37,11 +37,12 @@ public:
badtoken = 0x100,
endoffile = 0x101,
dotdotdot = 0x102,
scoperes = 0x103,
integer = 0x103,
charconstant = 0x104,
identifier = 0x105,
stringval = 0x106,
integer = 0x104,
charconstant = 0x105,
identifier = 0x106,
stringval = 0x107,
};
private:
uint4 type;
@@ -85,6 +86,8 @@ class GrammarLexer {
dot1,
dot2,
dot3,
scoperes1,
scoperes2,
punctuation,
endofline_comment,
c_comment,
@@ -169,12 +172,15 @@ class TypeDeclarator {
string ident; // variable identifier associated with type
string model; // name of model associated with function pointer
uint4 flags; // Specifiers qualifiers
int4 numBits; // Number of bits associated with declaration (0=unspecified)
public:
TypeDeclarator(void) { basetype=(Datatype *)0; flags=0; }
TypeDeclarator(const string &nm) { ident=nm; basetype=(Datatype *)0; flags=0; }
TypeDeclarator(void) { basetype=(Datatype *)0; flags=0; numBits=0; }
TypeDeclarator(const string &nm) { ident=nm; basetype=(Datatype *)0; flags=0; numBits=0; }
~TypeDeclarator(void);
Datatype *getBaseType(void) const { return basetype; }
int4 numModifiers(void) const { return mods.size(); }
int4 getNumBits(void) const { return numBits; }
void setNumBits(int4 val) { numBits = val; }
const string &getIdentifier(void) const { return ident; }
ProtoModel *getModel(Architecture *glb) const;
bool getPrototype(PrototypePieces &pieces,Architecture *glb) const;
@@ -39,7 +39,7 @@ static CParse *parse;
// Grammar taken from ISO/IEC 9899
%token DOTDOTDOT BADTOKEN STRUCT UNION ENUM DECLARATION_RESULT PARAM_RESULT
%token DOTDOTDOT BADTOKEN STRUCT UNION ENUM DECLARATION_RESULT PARAM_RESULT SCOPERES
%token <i> NUMBER
%token <str> IDENTIFIER
%token <str> STORAGE_CLASS_SPECIFIER TYPE_QUALIFIER FUNCTION_SPECIFIER
@@ -56,6 +56,7 @@ static CParse *parse;
%type <type> type_specifier struct_or_union_specifier enum_specifier
%type <enumer> enumerator
%type <vecenum> enumerator_list
%type <str> var_identifier
%%
document:
@@ -127,7 +128,7 @@ struct_declarator_list:
struct_declarator:
declarator { $$ = $1; }
// declarator ':' NUMBER
| declarator ':' NUMBER { $$ = $1; $1->setNumBits((int4)*$3); }
;
enum_specifier:
@@ -153,8 +154,13 @@ declarator:
| pointer direct_declarator { $$ = parse->mergePointer($1,$2); }
;
var_identifier:
IDENTIFIER { $$ = $1; }
| var_identifier SCOPERES IDENTIFIER { $$ = $1; $$->append("::"); $$->append(*$3); }
;
direct_declarator:
IDENTIFIER { $$ = parse->newDeclarator($1); }
var_identifier { $$ = parse->newDeclarator($1); }
| '(' declarator ')' { $$ = $2; }
| direct_declarator '[' type_qualifier_list assignment_expression ']' { $$ = parse->newArray($1,$3,$4); }
| direct_declarator '[' assignment_expression ']' { $$ = parse->newArray($1,0,$3); }
@@ -361,6 +367,9 @@ uint4 GrammarLexer::moveState(char lookahead)
state = punctuation;
bufstart = bufend-1;
break;
case ':':
state = scoperes1;
break;
case '-':
case '0':
case '1':
@@ -469,6 +478,19 @@ uint4 GrammarLexer::moveState(char lookahead)
state = start;
res = GrammarToken::dotdotdot;
break;
case scoperes1:
if (lookahead == ':') {
state = scoperes2;
}
else {
state = start;
res = ':';
}
break;
case scoperes2:
state = start;
res = GrammarToken::scoperes;
break;
case punctuation:
state = start;
res = (uint4)buffer[bufstart];
@@ -529,7 +551,7 @@ uint4 GrammarLexer::moveState(char lookahead)
}
else if ((lookahead>='a')&&(lookahead<='z')) {
}
else if (lookahead == '_' || lookahead == ':') {
else if (lookahead == '_') {
}
else {
state = start;
@@ -1035,6 +1057,8 @@ Datatype *CParse::newStruct(const string &ident,vector<TypeDeclarator *> *declis
{ // Build a new structure
TypeStruct *res = glb->types->getTypeStruct(ident); // Create stub (for recursion)
vector<TypeField> sublist;
vector<TypeBitField> bitlist;
bool isBigEndian = glb->getDefaultDataSpace()->isBigEndian();
for(uint4 i=0;i<declist->size();++i) {
TypeDeclarator *decl = (*declist)[i];
@@ -1043,14 +1067,14 @@ Datatype *CParse::newStruct(const string &ident,vector<TypeDeclarator *> *declis
glb->types->destroyType(res);
return (Datatype *)0;
}
sublist.emplace_back(0,-1,decl->getIdentifier(),decl->buildType(glb));
if (decl->getNumBits() != 0)
bitlist.emplace_back(sublist.size(),decl->getNumBits(),isBigEndian,decl->getIdentifier(),decl->buildType(glb));
else
sublist.emplace_back(0,-1,decl->getIdentifier(),decl->buildType(glb));
}
try {
int4 newSize;
int4 newAlign;
TypeStruct::assignFieldOffsets(sublist,newSize,newAlign);
glb->types->setFields(sublist,res,newSize,newAlign,0);
glb->types->assignRawFields(res,sublist,bitlist);
}
catch (LowlevelError &err) {
setError(err.explain);
@@ -1086,10 +1110,7 @@ Datatype *CParse::newUnion(const string &ident,vector<TypeDeclarator *> *declist
}
try {
int4 newSize;
int4 newAlign;
TypeUnion::assignFieldOffsets(sublist,newSize,newAlign,res);
glb->types->setFields(sublist,res,newSize,newAlign,0);
glb->types->assignRawFields(res,sublist);
}
catch (LowlevelError &err) {
setError(err.explain);
@@ -1282,6 +1303,8 @@ int4 CParse::lex(void)
return BADTOKEN;
case GrammarToken::dotdotdot:
return DOTDOTDOT;
case GrammarToken::scoperes:
return SCOPERES;
case GrammarToken::badtoken:
setError(lexer.getError()); // Error from lexer
return BADTOKEN;
@@ -1268,6 +1268,6 @@ ElementId ELEM_VAL = ElementId("val",8);
ElementId ELEM_VALUE = ElementId("value",9);
ElementId ELEM_VOID = ElementId("void",10);
ElementId ELEM_UNKNOWN = ElementId("XMLunknown",289); // Number serves as next open index
ElementId ELEM_UNKNOWN = ElementId("XMLunknown",290); // Number serves as next open index
} // End namespace ghidra
@@ -474,6 +474,7 @@ uintb PcodeOp::collapse(bool &markedInput) const {
/// The p-code op must be \e special, or an exception is thrown. The operation is performed
/// and if there is no evaluation error, the result is returned and \b evalError is set to \b false.
/// \param in is an array of input values
/// \param evalError passes back \b false if there is no evaluation error
/// \return the result of applying \b this operation to the input values
uintb PcodeOp::executeSimple(uintb *in,bool &evalError) const
@@ -732,8 +733,14 @@ uintb PcodeOp::getNZMaskLocal(bool cliploop) const
case CPUI_INT_ADD:
resmask = getIn(0)->getNZMask();
if (resmask!=fullmask) {
resmask |= getIn(1)->getNZMask();
resmask |= (resmask<<1); // Account for possible carries
uintb othermask = getIn(1)->getNZMask();
if ((othermask & resmask) == 0) {
resmask |= othermask;
}
else {
resmask |= othermask;
resmask |= (resmask << 1); // Account for possible carries
}
resmask &= fullmask;
}
break;
@@ -102,9 +102,10 @@ void OpBehavior::registerInstructions(vector<OpBehavior *> &inst,const Translate
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);
inst[CPUI_EXTRACT] = new OpBehavior(CPUI_EXTRACT,false);
inst[CPUI_ZPULL] = new OpBehavior(CPUI_ZPULL,false);
inst[CPUI_POPCOUNT] = new OpBehaviorPopcount();
inst[CPUI_LZCOUNT] = new OpBehaviorLzcount();
inst[CPUI_SPULL] = new OpBehavior(CPUI_SPULL,false);
}
/// \param sizeout is the size of the output in bytes
@@ -4,9 +4,9 @@
* 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.
@@ -123,11 +123,12 @@ enum OpCode {
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_ZPULL = 71, ///< Extract an unsigned bit-range
CPUI_POPCOUNT = 72, ///< Count the 1-bits
CPUI_LZCOUNT = 73, ///< Count the leading 0-bits
CPUI_SPULL = 74, ///< Extract a signed bit-range
CPUI_MAX = 74 ///< Value indicating the end of the op-code values
CPUI_MAX = 75 ///< 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
@@ -4,9 +4,9 @@
* 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.
@@ -252,6 +252,25 @@ void EmitMarkup::tagField(const string &name,syntax_highlight hl,const Datatype
encoder->closeElement(ELEM_FIELD);
}
void EmitMarkup::tagBitField(const string &name,syntax_highlight hl,const Datatype *ct,int4 id,const PcodeOp *op)
{
encoder->openElement(ELEM_BITFIELD);
if (hl != no_color)
encoder->writeUnsignedInteger(ATTRIB_COLOR,hl);
encoder->writeString(ATTRIB_NAME,ct->getName());
uint8 typeId = ct->getUnsizedId();
if (typeId != 0) {
encoder->writeUnsignedInteger(ATTRIB_ID, typeId);
}
encoder->writeSignedInteger(ATTRIB_OFF, id);
if (op != (const PcodeOp *)0)
encoder->writeUnsignedInteger(ATTRIB_OPREF, op->getTime());
encoder->writeString(ATTRIB_CONTENT,name);
encoder->closeElement(ELEM_BITFIELD);
}
void EmitMarkup::tagComment(const string &name,syntax_highlight hl,const AddrSpace *spc,uintb off)
{
@@ -407,6 +426,9 @@ void TokenSplit::print(Emit *emit) const
case field_t: // tagField
emit->tagField(tok,hl,ptr_second.ct,(int4)off,op);
break;
case bitfield_t: // tagBitField
emit->tagBitField(tok,hl,ptr_second.ct,(int4)off,op);
break;
case comm_t: // tagComment
emit->tagComment(tok,hl,ptr_second.spc,off);
break;
@@ -501,6 +523,9 @@ void TokenSplit::printDebug(ostream &s) const
case field_t: // tagField
s << "field_t";
break;
case bitfield_t: // tagBitField
s << "bitfield_t";
break;
case comm_t: // tagComment
s << "comm_t";
break;
@@ -1055,6 +1080,15 @@ void EmitPrettyPrint::tagField(const string &name,syntax_highlight hl,const Data
scan();
}
void EmitPrettyPrint::tagBitField(const string &name,syntax_highlight hl,const Datatype *ct,int4 id,const PcodeOp *op)
{
checkstring();
TokenSplit &tok( tokqueue.push() );
tok.tagBitField(name,hl,ct,id,op);
scan();
}
void EmitPrettyPrint::tagComment(const string &name,syntax_highlight hl,const AddrSpace *spc,uintb off)
{
@@ -273,11 +273,22 @@ public:
/// possibly with additional markup.
/// \param name is the character data for the identifier
/// \param hl indicates how the identifier should be highlighted
/// \param ct is the data-type associated with the field
/// \param ct is the structured data-type containing the field
/// \param off is the (byte) offset of the field within its structured data-type
/// \param op is the PcodeOp associated with the field (usually PTRSUB or SUBPIECE)
virtual void tagField(const string &name,syntax_highlight hl,const Datatype *ct,int4 off,const PcodeOp *op)=0;
/// \brief Emit an identifier for a bitfield within a structured data-type
///
/// A string representing an individual component of a structured data-type is emitted,
/// possibly with additional markup.
/// \param name is the character data for the identifier
/// \param hl indicates how the identifier should be highlighted
/// \param ct is the structured data-type containing the field
/// \param id is an identifier for the field within its structured data-type
/// \param op is the PcodeOp associated with the field (usually PTRSUB or SUBPIECE)
virtual void tagBitField(const string &name,syntax_highlight hl,const Datatype *ct,int4 id,const PcodeOp *op)=0;
/// \brief Emit a comment string as part of the generated source code
///
/// Individual comments can be broken up and emitted using multiple calls to this method,
@@ -527,6 +538,7 @@ public:
virtual void tagFuncName(const string &name,syntax_highlight hl,const Funcdata *fd,const PcodeOp *op);
virtual void tagType(const string &name,syntax_highlight hl,const Datatype *ct);
virtual void tagField(const string &name,syntax_highlight hl,const Datatype *ct,int4 off,const PcodeOp *op);
virtual void tagBitField(const string &name,syntax_highlight hl,const Datatype *ct,int4 id,const PcodeOp *op);
virtual void tagComment(const string &name,syntax_highlight hl,const AddrSpace *spc,uintb off);
virtual void tagLabel(const string &name,syntax_highlight hl,const AddrSpace *spc,uintb off);
virtual void tagCaseLabel(const string &name,syntax_highlight hl,const PcodeOp *op,uintb value);
@@ -576,6 +588,8 @@ public:
*s << name; }
virtual void tagField(const string &name,syntax_highlight hl,const Datatype *ct,int4 off,const PcodeOp *op) {
*s << name; }
virtual void tagBitField(const string &name,syntax_highlight hl,const Datatype *ct,int4 id,const PcodeOp *op) {
*s << name; }
virtual void tagComment(const string &name,syntax_highlight hl,const AddrSpace *spc,uintb off) {
*s << name; }
virtual void tagLabel(const string &name,syntax_highlight hl,const AddrSpace *spc,uintb off) {
@@ -642,6 +656,7 @@ public:
fnam_t, ///< A function identifier
type_t, ///< A data-type identifier
field_t, ///< A field name for a structured data-type
bitfield_t, ///< A bitfield name in a structured data-type
comm_t, ///< Part of a comment block
label_t, ///< A code label
case_t, ///< A case label
@@ -808,13 +823,24 @@ public:
///
/// \param name is the character data for the identifier
/// \param h indicates how the identifier should be highlighted
/// \param ct is the data-type associated with the field
/// \param ct is the structured data-type containing the field
/// \param o is the (byte) offset of the field within its structured data-type
/// \param inOp is the PcodeOp associated with the field (usually PTRSUB or SUBPIECE)
void tagField(const string &name,EmitMarkup::syntax_highlight h,const Datatype *ct,int4 o,const PcodeOp *inOp) {
tok = name; size = tok.size();
tagtype=field_t; delimtype=tokenstring; hl=h; ptr_second.ct=ct; off=(uintb)o; op=inOp; }
/// \brief Create an identifier for a bitfield within a structured data-type
///
/// \param name is the character data for the identifier
/// \param h indicates how the identifier should be highlighted
/// \param ct is the structured data-type containing the field
/// \param id is an identifier for the field within its structured data-type
/// \param inOp is the PcodeOp associated with the field (usually PTRSUB or SUBPIECE)
void tagBitField(const string &name,EmitMarkup::syntax_highlight h,const Datatype *ct,int4 id,const PcodeOp *inOp) {
tok = name; size = tok.size();
tagtype=bitfield_t; delimtype=tokenstring; hl=h; ptr_second.ct=ct; off=(uintb)id; op=inOp; }
/// \brief Create a comment string in the generated source code
///
/// \param name is the character data for the comment
@@ -1088,6 +1114,7 @@ public:
virtual void tagFuncName(const string &name,syntax_highlight hl,const Funcdata *fd,const PcodeOp *op);
virtual void tagType(const string &name,syntax_highlight hl,const Datatype *ct);
virtual void tagField(const string &name,syntax_highlight hl,const Datatype *ct,int4 off,const PcodeOp *op);
virtual void tagBitField(const string &name,syntax_highlight hl,const Datatype *ct,int4 id,const PcodeOp *op);
virtual void tagComment(const string &name,syntax_highlight hl,const AddrSpace *spc,uintb off);
virtual void tagLabel(const string &name,syntax_highlight hl,const AddrSpace *spc,uintb off);
virtual void tagCaseLabel(const string &name,syntax_highlight hl,const PcodeOp *op,uintb value);
@@ -368,6 +368,25 @@ bool PrintC::checkArrayDeref(const Varnode *vn) const
return true;
}
/// Bitfield accesses through a LOAD or STORE may have a PTRSUB accessing the
/// bitfield storage range. But with any additional PTRSUB or PTRADD, we can use
/// member syntax.
/// \param vn is the root of the pointer expression (the input into LOAD or STORE)
/// \param field is the bitfield being displayed
/// \return \b true if member syntax ('.') should be used or \b false for pointer syntax ('->')
bool PrintC::checkBitFieldMember(const Varnode *vn,const TypeBitField *field) const
{
if (field->bits.byteOffset != 0) { // Bitfield not at offset 0, a PTRSUB should be present
const PcodeOp *op;
if (!vn->isWritten()) return false;
op = vn->getDef();
if (op->code() != CPUI_PTRSUB) return false;
vn = op->getIn(0); // Skip this PTRSUB
}
return checkArrayDeref(vn);
}
/// Check that the output data-type is a pointer to an array and then that
/// the second data-type is a pointer to the element type (of the array).
/// If this holds and the input variable represents a symbol with an \e array data-type,
@@ -1264,13 +1283,59 @@ void PrintC::opNewOp(const PcodeOp *op)
void PrintC::opInsertOp(const PcodeOp *op)
{
opFunc(op); // If no other way to print it, print as functional operator
opFunc(op);
}
void PrintC::opExtractOp(const PcodeOp *op)
void PrintC::opZpullOp(const PcodeOp *op)
{
opFunc(op); // If no other way to print it, print as functional operator
PullExpression expr(op);
if (!expr.isValid()) {
opFunc(op); // If no other way to print it, print as functional operator
return;
}
if (expr.loadOp != (const PcodeOp *)0) {
uint4 m = mods;
if (checkBitFieldMember(expr.loadOp->getIn(1),expr.bitfield)) {
m |= print_load_value;
pushOp(&object_member,op);
}
else
pushOp(&pointer_member,op);
pushVn(expr.structPtr,expr.loadOp,m);
pushAtom(Atom(expr.bitfield->name,bitfieldtoken,EmitMarkup::no_color,expr.theStruct,expr.bitfield->ident,op));
}
else {
pushOp(&object_member,op);
pushSymbolDetail(op->getIn(0),op,true);
pushAtom(Atom(expr.bitfield->name,bitfieldtoken,EmitMarkup::no_color,expr.theStruct,expr.bitfield->ident,op));
}
}
void PrintC::opSpullOp(const PcodeOp *op)
{
PullExpression expr(op);
if (!expr.isValid()) {
opFunc(op); // If no other way to print it, print as functional operator
return;
}
if (expr.loadOp != (const PcodeOp *)0) {
uint4 m = mods;
if (checkBitFieldMember(expr.loadOp->getIn(1),expr.bitfield)) {
m |= print_load_value;
pushOp(&object_member,op);
}
else
pushOp(&pointer_member,op);
pushVn(expr.structPtr,expr.loadOp,m);
pushAtom(Atom(expr.bitfield->name,bitfieldtoken,EmitMarkup::no_color,expr.theStruct,expr.bitfield->ident,op));
}
else {
pushOp(&object_member,op);
pushSymbolDetail(op->getIn(0),op,true);
pushAtom(Atom(expr.bitfield->name,bitfieldtoken,EmitMarkup::no_color,expr.theStruct,expr.bitfield->ident,op));
}
}
/// \brief Push a constant with an integer data-type to the RPN stack
@@ -1982,6 +2047,10 @@ void PrintC::pushPartialSymbol(const Symbol *sym,int4 off,int4 sz,
ct = field->type;
succeeded = true;
}
else if (op->code() == CPUI_ZPULL || op->code() == CPUI_SPULL) {
// Cannot resolve final byte field because it is a bit field
break; // But we have fully resolved the Varnode
}
}
else if (ct->getMetatype() == TYPE_ARRAY) {
int4 el;
@@ -2468,21 +2537,31 @@ bool PrintC::emitInplaceOp(const PcodeOp *op)
void PrintC::emitExpression(const PcodeOp *op)
{
if (op->doesSpecialPrinting()) {
if (op->isCall()) {
emitConstructor(op);
return;
}
OpCode opc = op->code();
if (opc == CPUI_STORE) {
emitBitFieldStore(op);
return;
}
else if (opc == CPUI_INSERT) {
emitBitFieldExpression(op);
return;
}
else if (opc == CPUI_SUBPIECE) {
// Don't modify printing here
}
else
throw LowlevelError("Unsupported special printing");
}
const Varnode *outvn = op->getOut();
if (outvn != (Varnode *)0) {
if (option_inplace_ops && emitInplaceOp(op)) return;
pushOp(&assignment,op);
pushSymbolDetail(outvn,op,false);
}
else if (op->doesSpecialPrinting()) {
// Printing of constructor syntax
const PcodeOp *newop = op->getIn(1)->getDef();
outvn = newop->getOut();
pushOp(&assignment,newop);
pushSymbolDetail(outvn,newop,false);
opConstructor(op,true);
recurse();
return;
}
// If STORE, print *( ) = ( )
// If BRANCH, print nothing
@@ -2494,6 +2573,62 @@ void PrintC::emitExpression(const PcodeOp *op)
recurse();
}
void PrintC::emitConstructor(const PcodeOp *op)
{
// Printing of constructor syntax
const PcodeOp *newop = op->getIn(1)->getDef();
const Varnode *outvn = newop->getOut();
pushOp(&assignment,newop);
pushSymbolDetail(outvn,newop,false);
opConstructor(op,true);
recurse();
}
void PrintC::emitBitFieldStore(const PcodeOp *op)
{
InsertStoreExpression expr(op);
if (!expr.isValid()) {
op->getOpcode()->push(this,op,(PcodeOp *)0);
recurse();
return;
}
// We assume the STORE is a statement
pushOp(&assignment,op); // This is an assignment
uint4 m = mods;
if (checkBitFieldMember(op->getIn(1),expr.bitfield)) {
m |= print_store_value;
pushOp(&object_member,expr.insertOp);
}
else
pushOp(&pointer_member,expr.insertOp);
pushVn(expr.structPtr,op,m);
pushAtom(Atom(expr.bitfield->name,bitfieldtoken,EmitMarkup::no_color,expr.theStruct,expr.bitfield->ident,op));
// implied vn's pushed on in reverse order for efficiency
// see PrintLanguage::pushVnImplied
pushVn(expr.insertOp->getIn(1),op,mods);
recurse();
}
void PrintC::emitBitFieldExpression(const PcodeOp *op)
{
InsertExpression expr(op);
if (!expr.isValid()) {
opFunc(op); // If no other way to print it, print as functional operator
recurse();
return;
}
pushOp(&assignment,op); // This is an assignment
pushOp(&object_member,expr.insertOp);
pushPartialSymbol(expr.symbol, expr.offsetToBitStruct, expr.theStruct->getSize(), op->getOut(), op, -1, false);
pushAtom(Atom(expr.bitfield->name,bitfieldtoken,EmitMarkup::no_color,expr.theStruct,expr.bitfield->ident,op));
pushVn(op->getIn(1),op,mods);
recurse();
}
void PrintC::emitVarDecl(const Symbol *sym)
{
@@ -177,6 +177,7 @@ protected:
virtual bool doEmitWideCharPrefix(void) const;
bool checkArrayDeref(const Varnode *vn) const; ///< Determine whether a LOAD/STORE expression requires pointer '*' syntax
bool checkBitFieldMember(const Varnode *vn,const TypeBitField *field) const; ///< Determine whether a ZPULL/SPULL/INSERT should use '->' or '.' notation
bool checkAddressOfCast(const PcodeOp *op) const; ///< Check if CAST can be printed as an '&'
void emitStructDefinition(const TypeStruct *ct); ///< Emit the definition of a \e structure data-type
void emitEnumDefinition(const TypeEnum *ct); ///< Emit the definition of an \e enumeration data-type
@@ -226,6 +227,9 @@ protected:
virtual string genericTypeName(const Datatype *ct);
virtual void emitExpression(const PcodeOp *op);
virtual void emitConstructor(const PcodeOp *op);
virtual void emitBitFieldStore(const PcodeOp *op);
virtual void emitBitFieldExpression(const PcodeOp *op);
virtual void emitVarDecl(const Symbol *sym);
virtual void emitVarDeclStatement(const Symbol *sym);
virtual bool emitScopeVarDecls(const Scope *symScope,int4 cat);
@@ -339,7 +343,8 @@ public:
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 opZpullOp(const PcodeOp *op);
virtual void opSpullOp(const PcodeOp *op);
virtual void opPopcountOp(const PcodeOp *op) { opFunc(op); }
virtual void opLzcountOp(const PcodeOp *op) { opFunc(op); }
};
@@ -394,6 +394,9 @@ void PrintLanguage::emitAtom(const Atom &atom)
case fieldtoken:
emit->tagField(atom.name,atom.highlight,atom.ptr_second.ct,atom.offset,atom.op);
break;
case bitfieldtoken:
emit->tagBitField(atom.name,atom.highlight,atom.ptr_second.ct,atom.offset,atom.op);
break;
case casetoken:
emit->tagCaseLabel(atom.name, atom.highlight, atom.op, atom.ptr_second.intValue);
break;
@@ -167,6 +167,7 @@ public:
optoken, ///< Emit atom as operator
typetoken, ///< Emit atom as operator
fieldtoken, ///< Emit atom as structure field
bitfieldtoken, ///< Emit atom as structure bitfield
casetoken, ///< Emit atom as a \e case label
blanktoken ///< For anonymous types
};
@@ -429,6 +430,24 @@ protected:
/// \param op is the given PcodeOp performing the final operation of the expression
virtual void emitExpression(const PcodeOp *op)=0;
/// \brief Emit a call as a \e constructor expression
///
/// Use language specific constructor syntax to represent the CALL.
/// \param op is the CALL op
virtual void emitConstructor(const PcodeOp *op)=0;
/// \brief Emit STORE to a bit field
///
/// Printing for the sequence: `STORE( ptr, INSERT( LOAD(ptr), val, #pos, #sz ) )`
/// \param op is the STORE
virtual void emitBitFieldStore(const PcodeOp *op)=0;
/// \brief Emit expression writing to a bitfield
///
/// Printing for an expression rooted at INSERT
/// \param op is the INSERT
virtual void emitBitFieldExpression(const PcodeOp *op)=0;
/// \brief Emit a function declaration
///
/// This prints the formal defining prototype for a function.
@@ -577,9 +596,10 @@ public:
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 opZpullOp(const PcodeOp *op)=0; ///< Emit a ZPULL operator
virtual void opPopcountOp(const PcodeOp *op)=0; ///< Emit a POPCOUNT operator
virtual void opLzcountOp(const PcodeOp *op)=0; ///< Emit a LZCOUNT operator
virtual void opSpullOp(const PcodeOp *op)=0; ///< Emit an SPULL operator
virtual string unnamedField(int4 off,int4 size); ///< Generate an artificial field name
static int4 mostNaturalBase(uintb val); ///< Determine the most natural base for an integer
@@ -10945,7 +10945,8 @@ int4 RuleExpandLoad::applyOp(PcodeOp *op,Funcdata &data)
if (elType->getSize() < outSize + offset) return 0;
type_metatype meta = elType->getMetatype();
if (meta == TYPE_UNKNOWN) return 0;
if (meta == TYPE_UNKNOWN || meta == TYPE_STRUCT || meta == TYPE_ARRAY || meta == TYPE_UNION
|| meta == TYPE_PARTIALSTRUCT || meta == TYPE_PARTIALUNION) return 0;
bool addForm = checkAndComparison(outVn);
AddrSpace *spc = op->getIn(0)->getSpaceFromConst();
int4 lsbCut = 0;
@@ -2764,6 +2764,7 @@ bool SplitDatatype::splitLoad(PcodeOp *loadOp,Datatype *inType)
if (copyOp != (PcodeOp *)0) {
OpCode opc = copyOp->code();
if (opc == CPUI_STORE) return false; // Handled by RuleSplitStore
if (opc == CPUI_ZPULL || opc == CPUI_SPULL) return false;
if (opc != CPUI_COPY)
copyOp = (PcodeOp *)0;
}
File diff suppressed because it is too large Load Diff
@@ -68,6 +68,7 @@ extern ElementId ELEM_TYPEREF; ///< Marshaling element \<typeref>
//extern ElementId ELEM_USE_MS_CONVENTION; ///< Marshaling element \<use_MS_convention>
extern ElementId ELEM_WCHAR_SIZE; ///< Marshaling element \<wchar_size>
//extern ElementId ELEM_ZERO_LENGTH_BOUNDARY; ///< Marshaling element \<zero_length_boundary>
extern ElementId ELEM_BITFIELD; ///< Marshaling element \<bitfield>
/// Print a hex dump of a data buffer to stream
extern void print_data(ostream &s,uint1 *buffer,int4 size,const Address &baseaddr);
@@ -155,6 +156,7 @@ extern type_class metatype2typeclass(type_metatype meta);
class Architecture; // Forward declarations
class PcodeOp;
class Scope;
class TypeStruct;
class TypeFactory;
class TypeField;
struct DatatypeCompare;
@@ -182,7 +184,8 @@ protected:
force_format = 0x7000, ///< 3-bits encoding display format, 0=none, 1=hex, 2=dec, 3=oct, 4=bin, 5=char
truncate_bigendian = 0x8000, ///< Pointer can be truncated and is big endian
pointer_to_array = 0x10000, ///< Data-type is a pointer to an array
warning_issued = 0x20000 ///< Data-type has an associated \e warning string
warning_issued = 0x20000, ///< Data-type has an associated \e warning string
has_bitfields = 0x40000 ///< Data-type contains bitfields
};
friend class TypeFactory;
friend struct DatatypeCompare;
@@ -230,6 +233,7 @@ public:
bool isIncomplete(void) const { return (flags & type_incomplete)!=0; } ///< Is \b this an incompletely defined data-type
bool needsResolution(void) const { return (flags & needs_resolution)!=0; } ///< Is \b this a union or a pointer to union
bool hasWarning(void) const { return (flags & warning_issued)!=0; } ///< Has a \e warning been issued about \b this data-type
bool hasBitfields(void) const { return (flags & has_bitfields)!=0; } ///< Return \b true if \b this contains/overlaps bitfields
uint4 getInheritable(void) const { return (flags & coretype); } ///< Get properties pointers inherit
uint4 getDisplayFormat(void) const; ///< Get the display format for constants with \b this data-type
type_metatype getMetatype(void) const { return metatype; } ///< Get the type \b meta-type
@@ -266,6 +270,14 @@ public:
/// \return the i-th component sub-type
virtual Datatype *getDepend(int4 index) const { return (Datatype *)0; }
/// \brief If \b this is a pointer, return the large data-type \b this points into
///
/// If \b this is not a pointer, null is returned. For ordinary pointers, the data-type being pointed
/// at is returned. For a relative pointer, the innermost structured data-type is returned and the offset passed back.
/// \param off is used to pass back any offset
/// \return the data-type being pointed into or null
virtual Datatype *getPtrInto(int4 &off) const { return (Datatype *)0; }
/// \brief Print (part of) the name of \b this data-type as short prefix for a label
///
/// This is used for building variable names to give some indication of the variable's underlying data-type
@@ -292,14 +304,50 @@ public:
/// \brief A field within a structure or union
class TypeField {
public:
int4 ident; ///< Id for identifying \b this within its containing structure or union
int4 ident; ///< Identifier of \b this within its containing structure or union
int4 offset; ///< Offset (into containing structure or union) of subfield
string name; ///< Name of subfield
Datatype *type; ///< Data-type of subfield
TypeField(Decoder &decoder,TypeFactory &typegrp); ///< Restore \b this field from a stream
TypeField(int4 id,int4 off,const string &nm,Datatype *ct) { ident=id; offset=off; name=nm; type=ct; } ///< Construct from components
bool operator<(const TypeField &op2) const { return (offset < op2.offset); } ///< Compare based on offset
void encode(Encoder &encoder) const; ///< Encode \b this field to a stream
int4 compare(const TypeField &op2) const; ///< Compare \b this with another TypeField for propagation ordering
int4 compareDependency(const TypeField &op2) const; ///< Compare \b this with another TypeField for functional equivalence
void encode(Encoder &encoder) const; ///< Encode \b this field to a stream
static bool compareMaxByte(int4 off,const TypeField &field) { ///< Compare field end-point to the given offset
return (off < field.offset + field.type->getSize());
}
};
/// \brief A field within a structure that is not aligned or sized on byte boundaries
class TypeBitField {
public:
string name; ///< Name of bitfield
Datatype *type; ///< Underlying (integer) data-type
BitRange bits; ///< Description of the bitfield within its structure
int4 ident; ///< Identifier of \b this within containing structure
TypeBitField(Decoder &decoder,TypeFactory &typegrp); ///< Restore \b this bitfield from a stream
TypeBitField(int4 id,int4 numBits,bool isBigEndian,const string &nm,Datatype *ct); ///< Construct from components
int4 compare(const TypeBitField &op2) const; ///< Compare definition of \b this with another TypeBitField for propagation ordering
int4 compareDependency(const TypeBitField &op2) const; ///< Compare \b this with another TypeBitField for functional equivalence
void encode(Encoder &encoder) const; ///< Encode \b this bitfield to a stream
static bool compareMaxByte(int4 off,const TypeBitField &bitfield) { ///< Compare byte container end-point to the given offset
return (off < bitfield.bits.byteOffset + bitfield.bits.byteSize);
}
};
/// \brief Helper class for collecting bitfields intersecting a byte range within a (possibly nested) structure
///
/// A bitfield description, along with its immediate container, and offset within a root container all in one record.
class BitFieldTriple {
public:
const TypeStruct *immedContainer; ///< Immediate container of the bitfield
const TypeBitField *bitfield; ///< Description of the bitfield
int4 offset; ///< Byte offset of the immediate container within parent
BitFieldTriple(const TypeStruct *contain,const TypeBitField *bits,int4 off) {
immedContainer = contain; bitfield = bits; offset = off; } ///< Constructor
/// \brief Comparator putting bitfields in byte order, least to most significant
static bool compare(const BitFieldTriple &op1,const BitFieldTriple &op2);
};
/// Compare two Datatype pointers for equivalence of their description
@@ -421,6 +469,7 @@ public:
virtual Datatype *getSubType(int8 off,int8 *newoff) const;
virtual int4 numDepend(void) const { return 1; }
virtual Datatype *getDepend(int4 index) const { return ptrto; }
virtual Datatype *getPtrInto(int4 &off) const { off=0; return ptrto; }
virtual void printNameBase(ostream &s) const { s << 'p'; ptrto->printNameBase(s); }
virtual int4 compare(const Datatype &op,int4 level) const;
virtual int4 compareDependency(const Datatype &op) const;
@@ -508,16 +557,32 @@ public:
class TypeStruct : public Datatype {
protected:
friend class TypeFactory;
vector<TypeField> field; ///< The list of fields
void setFields(const vector<TypeField> &fd,int4 fixedSize,int4 fixedAlign); ///< Establish fields for \b this
vector<TypeField> field; ///< List of fields
vector<TypeBitField> bitfield; ///< List of fields not aligned/sized on byte boundaries
/// \brief Helper function for decoding TypeField objects
struct FieldAccum {
int4 lastOff; ///< Offset of last field
int4 calcSize; ///< Current accumulated size of structure
int4 calcAlign; ///< Maximum alignment seen so far
string warning; ///< Warning(s) produced during decode
};
void setFields(const vector<TypeField> &fd,const vector<TypeBitField> &bit,int4 fixedSize,int4 fixedAlign); ///< Establish fields for \b this
int4 getFieldIter(int4 off) const; ///< Get index into field list
int4 getLowerBoundField(int4 off) const; ///< Get index of last field before or equal to given offset
void decodeField(Decoder &decoder,TypeFactory &typegrp,FieldAccum &accum);
void decodeBitField(Decoder &decoder,TypeFactory &typegrp,FieldAccum &accum);
string decodeFields(Decoder &decoder,TypeFactory &typegrp); ///< Restore fields from a stream
static void assignContiguousBitfields(vector<TypeBitField> &bitlist,int4 &pos,int4 &offset,int4 &newAlign);
public:
TypeStruct(const TypeStruct &op); ///< Construct from another TypeStruct
TypeStruct(void) : Datatype(0,-1,TYPE_STRUCT) { flags |= type_incomplete; } ///< Construct incomplete/empty TypeStruct
vector<TypeField>::const_iterator beginField(void) const { return field.begin(); } ///< Beginning of fields
vector<TypeField>::const_iterator endField(void) const { return field.end(); } ///< End of fields
int4 numBitFields(void) const { return bitfield.size(); } ///< Return the number of bitfields contained by \b this
const TypeBitField &getBitField(int4 i) const { return bitfield[i]; } ///< Return the i-th bitfield
const TypeBitField *findMatchingBitField(const BitRange &range) const; ///< Return bitfield matching the given bit range
void collectBitFields(int4 baseOffset,vector<BitFieldTriple> &res,int4 offset,int4 sz) const; ///< Collect bitfield records that overlap given range
bool hasBitFieldsInRange(int4 offset,int4 sz) const; ///< Return \b true if \b this structure has 1 or more bitfields in the given byte range
virtual const TypeField *findTruncation(int8 off,int4 sz,const PcodeOp *op,int4 slot,int8 &newoff) const;
virtual Datatype *getSubType(int8 off,int8 *newoff) const;
virtual Datatype *nearestArrayedComponentForward(int8 off,int8 *newoff,int8 *elSize) const;
@@ -532,7 +597,7 @@ public:
virtual Datatype *resolveInFlow(PcodeOp *op,int4 slot);
virtual Datatype* findResolve(const PcodeOp *op,int4 slot);
virtual int4 findCompatibleResolve(Datatype *ct) const;
static void assignFieldOffsets(vector<TypeField> &list,int4 &newSize,int4 &newAlign); ///< Assign field offsets
static void assignFieldOffsets(vector<TypeField> &list,vector<TypeBitField> &bitlist,int4 &newSize,int4 &newAlign,uint4 &flags);
static int4 scoreSingleComponent(Datatype *parent,PcodeOp *op,int4 slot); ///< Determine best type fit for given PcodeOp use
};
@@ -674,6 +739,7 @@ public:
/// \return the offset value in \e byte units
int4 getByteOffset(void) const { return offset; }
virtual void printRaw(ostream &s) const;
virtual Datatype *getPtrInto(int4 &off) const;
virtual int4 compare(const Datatype &op,int4 level) const;
virtual int4 compareDependency(const Datatype &op) const;
virtual Datatype *clone(void) const { return new TypePointerRel(*this); }
@@ -798,6 +864,8 @@ class TypeFactory {
void insertWarning(Datatype *dt,string warn); ///< Register a new data-type warning with \b this factory
void removeWarning(Datatype *dt); ///< Remove the warning associated with the given data-type
void resolveIncompleteTypedefs(void); ///< Redefine incomplete typedefs of data-types that are now complete
void setFields(const vector<TypeField> &fd,const vector<TypeBitField> &bit,TypeStruct *ot,int4 newSize,int4 newAlign,uint4 flags);
void setFields(const vector<TypeField> &fd,TypeUnion *ot,int4 newSize,int4 newAlign,uint4 flags); ///< Set fields on a TypeUnion
protected:
Architecture *glb; ///< The Architecture object that owns this TypeFactory
Datatype *findByIdLocal(const string &nm,uint8 id) const; ///< Search locally by name and id
@@ -820,8 +888,6 @@ public:
Datatype *findByName(const string &n); ///< Return type of given name
Datatype *setName(Datatype *ct,const string &n); ///< Set the given types name
void setDisplayFormat(Datatype *ct,uint4 format); ///< Set the display format associated with the given data-type
void setFields(const vector<TypeField> &fd,TypeStruct *ot,int4 newSize,int4 newAlign,uint4 flags); ///< Set fields on a TypeStruct
void setFields(const vector<TypeField> &fd,TypeUnion *ot,int4 newSize,int4 newAlign,uint4 flags); ///< Set fields on a TypeUnion
void setPrototype(const FuncProto *fp,TypeCode *newCode,uint4 flags); ///< Set the prototype on a TypeCode
void setEnumValues(const map<uintb,string> &nmap,TypeEnum *te); ///< Set named values for an enumeration
Datatype *decodeType(Decoder &decoder); ///< Restore Datatype from a stream
@@ -849,7 +915,10 @@ public:
TypePointerRel *getTypePointerRel(int4 sz,Datatype *parent,Datatype *ptrTo,int4 ws,int4 off,const string &nm);
TypePointer *getTypePointerWithSpace(Datatype *ptrTo,AddrSpace *spc,const string &nm);
TypePointer *resizePointer(TypePointer *ptr,int4 newSize); ///< Build a resized pointer based on the given pointer
Datatype *resizeInteger(Datatype *ct,int4 newSize); ///< Build a resized integer based on the given integer
Datatype *getExactPiece(Datatype *ct,int4 offset,int4 size); ///< Get the data-type associated with piece of a structured data-type
void assignRawFields(TypeStruct *ct,vector<TypeField> &fd,vector<TypeBitField> &bit);
void assignRawFields(TypeUnion *ct,vector<TypeField> &fd);
void destroyType(Datatype *ct); ///< Remove a data-type from \b this
Datatype *concretize(Datatype *ct); ///< Convert given data-type to concrete form
void dependentOrder(vector<Datatype *> &deporder) const; ///< Place all data-types in dependency order
@@ -102,9 +102,10 @@ void TypeOp::registerInstructions(vector<TypeOp *> &inst,TypeFactory *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_ZPULL] = new TypeOpZpull(tlst);
inst[CPUI_POPCOUNT] = new TypeOpPopcount(tlst);
inst[CPUI_LZCOUNT] = new TypeOpLzcount(tlst);
inst[CPUI_SPULL] = new TypeOpSpull(tlst);
}
/// Change basic data-type info (signed vs unsigned) and operator names ( '>>' vs '>>>' )
@@ -521,6 +522,7 @@ Datatype *TypeOpStore::getInputCast(const PcodeOp *op,int4 slot,const CastStrate
{
if (slot==0) return (Datatype *)0;
if (op->doesSpecialPrinting()) return (Datatype *)0;
const Varnode *pointerVn = op->getIn(1);
Datatype *pointerType = pointerVn->getHighTypeReadFacing(op);
Datatype *pointedToType = pointerType;
@@ -2535,19 +2537,31 @@ TypeOpInsert::TypeOpInsert(TypeFactory *t)
Datatype *TypeOpInsert::getInputLocal(const PcodeOp *op,int4 slot) const
{
if (slot == 0)
if (slot <= 1)
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)
Datatype *TypeOpInsert::getInputCast(const PcodeOp *op,int4 slot,const CastStrategy *castStrategy) const
{
return (Datatype *)0; // Never need casts
}
Datatype *TypeOpInsert::getOutputToken(const PcodeOp *op,CastStrategy *castStrategy) const
{
return op->getOut()->getHighTypeDefFacing();
}
TypeOpZpull::TypeOpZpull(TypeFactory *t)
: TypeOpFunc(t,CPUI_ZPULL,"ZPULL",TYPE_UINT,TYPE_INT)
{
opflags = PcodeOp::ternary;
behave = new OpBehavior(CPUI_EXTRACT,false); // Dummy behavior
behave = new OpBehavior(CPUI_ZPULL,false); // Dummy behavior
}
Datatype *TypeOpExtract::getInputLocal(const PcodeOp *op,int4 slot) const
Datatype *TypeOpZpull::getInputLocal(const PcodeOp *op,int4 slot) const
{
if (slot == 0)
@@ -2555,6 +2569,45 @@ Datatype *TypeOpExtract::getInputLocal(const PcodeOp *op,int4 slot) const
return TypeOpFunc::getInputLocal(op, slot);
}
Datatype *TypeOpZpull::getInputCast(const PcodeOp *op,int4 slot,const CastStrategy *castStrategy) const
{
return (Datatype *)0; // Never need casts
}
Datatype *TypeOpZpull::getOutputToken(const PcodeOp *op,CastStrategy *castStrategy) const
{
return op->getOut()->getHighTypeDefFacing();
}
TypeOpSpull::TypeOpSpull(TypeFactory *t)
: TypeOpFunc(t,CPUI_SPULL,"SPULL",TYPE_INT,TYPE_INT)
{
opflags = PcodeOp::ternary;
behave = new OpBehavior(CPUI_SPULL,false); // Dummy behavior
}
Datatype *TypeOpSpull::getInputLocal(const PcodeOp *op,int4 slot) const
{
if (slot == 0)
return tlst->getBase(op->getIn(slot)->getSize(),TYPE_UNKNOWN);
return TypeOpFunc::getInputLocal(op, slot);
}
Datatype *TypeOpSpull::getInputCast(const PcodeOp *op,int4 slot,const CastStrategy *castStrategy) const
{
return (Datatype *)0; // Never need casts
}
Datatype *TypeOpSpull::getOutputToken(const PcodeOp *op,CastStrategy *castStrategy) const
{
return op->getOut()->getHighTypeDefFacing();
}
TypeOpPopcount::TypeOpPopcount(TypeFactory *t)
: TypeOpFunc(t,CPUI_POPCOUNT,"POPCOUNT",TYPE_INT,TYPE_UNKNOWN)
{
@@ -887,15 +887,29 @@ class TypeOpInsert : public TypeOpFunc {
public:
TypeOpInsert(TypeFactory *t); ///< Constructor
virtual Datatype *getInputLocal(const PcodeOp *op,int4 slot) const;
virtual Datatype *getInputCast(const PcodeOp *op,int4 slot,const CastStrategy *castStrategy) const;
virtual Datatype *getOutputToken(const PcodeOp *op,CastStrategy *castStrategy) const;
virtual void push(PrintLanguage *lng,const PcodeOp *op,const PcodeOp *readOp) const { lng->opInsertOp(op); }
};
/// \brief Information about the EXTRACT op-code
class TypeOpExtract : public TypeOpFunc {
/// \brief Information about the ZPULL op-code
class TypeOpZpull : public TypeOpFunc {
public:
TypeOpExtract(TypeFactory *t); ///< Constructor
TypeOpZpull(TypeFactory *t); ///< Constructor
virtual Datatype *getInputLocal(const PcodeOp *op,int4 slot) const;
virtual void push(PrintLanguage *lng,const PcodeOp *op,const PcodeOp *readOp) const { lng->opExtractOp(op); }
virtual Datatype *getInputCast(const PcodeOp *op,int4 slot,const CastStrategy *castStrategy) const;
virtual Datatype *getOutputToken(const PcodeOp *op,CastStrategy *castStrategy) const;
virtual void push(PrintLanguage *lng,const PcodeOp *op,const PcodeOp *readOp) const { lng->opZpullOp(op); }
};
/// \brief Information about the SPULL op-code
class TypeOpSpull : public TypeOpFunc {
public:
TypeOpSpull(TypeFactory *t); ///< Constructor
virtual Datatype *getInputLocal(const PcodeOp *op,int4 slot) const;
virtual Datatype *getInputCast(const PcodeOp *op,int4 slot,const CastStrategy *castStrategy) const;
virtual Datatype *getOutputToken(const PcodeOp *op,CastStrategy *castStrategy) const;
virtual void push(PrintLanguage *lng,const PcodeOp *op,const PcodeOp *readOp) const { lng->opSpullOp(op); }
};
/// \brief Information about the POPCOUNT op-code
@@ -0,0 +1,117 @@
<decompilertest>
<binaryimage arch="x86:LE:64:default:gcc">
<bytechunk space="ram" offset="0x10027f" readonly="true">
89
f083e00f83fe090f9ec2c1e2078d04c5
0200000009d0880783c61483e61f0fb6
470883e0e009f08847080fb747086625
7fc080cc3266894708c383fe01742183
fe0274230fb60701c03c2f7e2c0fb607
c0e8073c0119c0258403000083c064c3
0fb60783e007c30fb6570889d083e01f
c0ea0583e20301d0c30fb64708c0e805
83e003c34883ec188d04fd0800000083
e07883ff090f9ec1c1e10783e60709c8
09f0884424040fb644240c83e08083c8
2a8844240c83e27f89d0c1e0070fb754
240c6681e27fc009c2668954240c488d
7c2404e8a8fcffff4883c418c34883ec
1089fe488d7c2404e812ffffff807c24
040079170fb644240483e0070fb65424
0c83e21f01d04883c410c3f644240440
750e0fb744240c66c1e80783e07febe6
0fb644240cc0e80583e003ebd90fb617
89d183e107b80100000080f905744983
e278b80200000080fa68743cb8030000
00803f0078320fb6570889d183e11fb8
0400000080f91b741fb805000000f6c2
6074150fb747086625803f663d00210f
94c00fb6c083c006c34883ec1089fe48
8d7c2404e866feffff0fb644240483e0
7fba010000003c5d74160fb744240c66
25e03f663d80100f94c20fb6d283c202
89d04883c410c3
</bytechunk>
<bytechunk space="ram" offset="0x10045a" readonly="true">
0fb60701c0c0
f8040fbec0034704c30fb647088d5001
83e21f83e0e009d0884708c3
</bytechunk>
<symbol space="ram" offset="0x10027f" name="dosomething"/>
<symbol space="ram" offset="0x1002ba" name="doload"/>
<symbol space="ram" offset="0x100304" name="dostackinsert"/>
<symbol space="ram" offset="0x10035d" name="dostackextract"/>
<symbol space="ram" offset="0x1003ad" name="docompare"/>
<symbol space="ram" offset="0x100409" name="doublecompare"/>
<symbol space="ram" offset="0x10045a" name="addsigned"/>
<symbol space="ram" offset="0x100469" name="increment"/>
</binaryimage>
<script>
<com>map fun r0x100000 receive</com>
<com>parse line struct myfoo { uint4 field3:3; int4 sfield4:4; bool fieldb:1; char a; char b; char c; int4 d; uint4 field5:5; uint4 field2:2; uint4 field7:7; };</com>
<com>parse line extern void receive(myfoo *ptr);</com>
<com>parse line extern void dosomething(myfoo *ptr,int4 val);</com>
<com>parse line extern int4 doload(myfoo *loadptr,int4 loadval);</com>
<com>parse line extern void dostackinsert(int4 stki_a,uint4 stki_b,uint4 stki_c);</com>
<com>parse line extern int4 docompare(myfoo *ptrcomp);</com>
<com>parse line extern int4 doublecompare(int4 val);</com>
<com>parse line extern int4 addsigned(myfoo *ap);</com>
<com>parse line extern void increment(myfoo *ip);</com>
<com>lo fu dosomething</com>
<com>decompile</com>
<com>print C</com>
<com>lo fu doload</com>
<com>decompile</com>
<com>print C</com>
<com>lo fu dostackinsert</com>
<com>decompile</com>
<com>print C</com>
<com>lo fu dostackextract</com>
<com>decompile</com>
<com>print C</com>
<com>lo fu docompare</com>
<com>decompile</com>
<com>print C</com>
<com>lo fu doublecompare</com>
<com>decompile</com>
<com>print C</com>
<com>lo fu addsigned</com>
<com>decompile</com>
<com>print C</com>
<com>lo fu increment</com>
<com>decompile</com>
<com>print C</com>
<com>quit</com>
</script>
<stringmatch name="Bitfields #1" min="1" max="1">ptr-&gt;field3 = 2;</stringmatch>
<stringmatch name="Bitfields #2" min="1" max="1">ptr-&gt;fieldb = val &lt; 10;</stringmatch>
<stringmatch name="Bitfields #3" min="1" max="1">ptr-&gt;sfield4 = val;</stringmatch>
<stringmatch name="Bitfields #4" min="1" max="1">ptr-&gt;field5 = \(uint1\)val \+ 0x14;</stringmatch>
<stringmatch name="Bitfields #5" min="1" max="1">ptr-&gt;field7 = 100;</stringmatch>
<stringmatch name="Bitfields #6" min="1" max="1">return loadptr-&gt;field3;</stringmatch>
<stringmatch name="Bitfields #7" min="1" max="1">if \(.*2.* &lt; loadptr-&gt;sfield4\)</stringmatch>
<stringmatch name="Bitfields #8" min="1" max="1">-\(uint4\)!loadptr-&gt;fieldb &amp; 900</stringmatch>
<stringmatch name="Bitfields #9" min="1" max="1">return loadptr-&gt;field2;</stringmatch>
<stringmatch name="Bitfields #10" min="1" max="1">return loadptr-&gt;field5 \+ loadptr-&gt;field2;</stringmatch>
<stringmatch name="Bitfields #11" min="1" max="1">mStack_14\.fieldb = stki_a &lt; 10;</stringmatch>
<stringmatch name="Bitfields #12" min="1" max="1">mStack_14\.sfield4 = \(char\)stki_a \+ 1;</stringmatch>
<stringmatch name="Bitfields #13" min="1" max="1">mStack_14\.field3 = stki_b;</stringmatch>
<stringmatch name="Bitfields #14" min="1" max="1">mStack_14\.field2 = 1;</stringmatch>
<stringmatch name="Bitfields #15" min="1" max="1">mStack_14\.field5 = 10;</stringmatch>
<stringmatch name="Bitfields #16" min="1" max="1">mStack_14\.field7 = stki_c;</stringmatch>
<stringmatch name="Bitfields #17" min="1" max="1">if \(mStack_c\.fieldb\)</stringmatch>
<stringmatch name="Bitfields #18" min="1" max="1">uVar1 = mStack_c\.field3 \+ mStack_c\.field5;</stringmatch>
<stringmatch name="Bitfields #19" min="1" max="1">if \(mStack_c\.sfield4 &lt; 0\)</stringmatch>
<stringmatch name="Bitfields #20" min="1" max="1">uVar1 = mStack_c\.field2;</stringmatch>
<stringmatch name="Bitfields #21" min="1" max="1">uVar1 = mStack_c\.field7;</stringmatch>
<stringmatch name="Bitfields #22" min="1" max="1">ptrcomp-&gt;field3 .= 5\)</stringmatch>
<stringmatch name="Bitfields #23" min="1" max="1">ptrcomp-&gt;sfield4 .= -3\)</stringmatch>
<stringmatch name="Bitfields #24" min="1" max="1">ptrcomp-&gt;fieldb\)</stringmatch>
<stringmatch name="Bitfields #25" min="1" max="1">ptrcomp-&gt;field5 .= 0x1b\)</stringmatch>
<stringmatch name="Bitfields #26" min="1" max="1">ptrcomp-&gt;field2 .= 0\)</stringmatch>
<stringmatch name="Bitfields #27" min="1" max="1">ptrcomp-&gt;field7 .= 0x42\)</stringmatch>
<stringmatch name="Bitfields #28" min="1" max="1">\(mStack_c\.field3 .= 5 .. mStack_c\.sfield4 .= -5\)</stringmatch>
<stringmatch name="Bitfields #29" min="1" max="1">\(mStack_c\.field2 .= 0 .. mStack_c\.field7 .= 0x21\)</stringmatch>
<stringmatch name="Bitfields #30" min="1" max="1">return ap-&gt;sfield4 \+ ap-&gt;d;</stringmatch>
<stringmatch name="Bitfields #31" min="1" max="1">ip-&gt;field5 = ip-&gt;field5 \+ 1;</stringmatch>
</decompilertest>
@@ -0,0 +1,148 @@
<decompilertest>
<binaryimage arch="MIPS:BE:32:default:default">
<bytechunk space="ram" offset="0x100000" readonly="true">
0005110028a3000a3442000400431025
a082000024a5001430a5001f000529c0
94820008000000003042f00000451025
3442006403e00008a482000800000000
</bytechunk>
<bytechunk space="ram" offset="0x100100" readonly="true">
2402000110a2000f2402000210a20012
00000000808200000000000028420030
14400015000000008082000000000000
30420001144000150000000003e00008
240203e8808200000000000000021042
03e00008304200078483000800000000
000311c23042001f00031b0230630003
03e00008004310218482000800000000
0002130203e000083042000303e00008
24020064
</bytechunk>
<bytechunk space="ram" offset="0x100200" readonly="true">
27bdffd0afbf002c2483000100031900
93a200182884000a3042000e00431025
0044102530a50007000528402403fff1
0043102400451025a3a2001897a20020
000000003042c00030c6007f34421500
00461025a7a2002027a400180c100000
000000008fbf002c0000000003e00008
27bd0030
</bytechunk>
<bytechunk space="ram" offset="0x100300" readonly="true">
27bdffd0afbf002c27a400180c100000
0000000083a200180000000030420001
1040000e0000000083a2001800000000
000210423042000787a3002000000000
000319c23063001f004310218fbf002c
0000000003e0000827bd003083a20018
00000000044000040000000087a20020
1000fff63042007f87a2002000000000
000213021000fff13042000300000000
</bytechunk>
<bytechunk space="ram" offset="0x100400" readonly="true">
90820000000000003045000e2403000a
10a30015240300d0304200f010430014
00000000808200000000000030420001
1440001124030d809482000800000000
30440f801083000e304330001060000e
240300423042007f1043000d00000000
03e000082402000603e0000824020001
03e000082402000203e0000824020003
03e000082402000403e0000824020005
03e0000824020007
</bytechunk>
<bytechunk space="ram" offset="0x100500" readonly="true">
27bdffd0afbf002c27a400180c100000
0000000083a2001800000000304200fe
240300ba1043000b2403002187a20020
000000003042307f1043000224020003
240200028fbf002c0000000003e00008
27bd00301000fffb2402000100000000
</bytechunk>
<bytechunk space="ram" offset="0x100600" readonly="true">
8082000000000000000211038c830004
03e0000800431021
</bytechunk>
<bytechunk space="ram" offset="0x100700" readonly="true">
8482000800000000000211c224420001
3042001f000211c09483000800000000
3063f07f0062102503e00008a4820008
</bytechunk>
<symbol space="ram" offset="0x100000" name="dosomething"/>
<symbol space="ram" offset="0x100100" name="doload"/>
<symbol space="ram" offset="0x100200" name="dostackinsert"/>
<symbol space="ram" offset="0x100300" name="dostackextract"/>
<symbol space="ram" offset="0x100400" name="docompare"/>
<symbol space="ram" offset="0x100500" name="doublecompare"/>
<symbol space="ram" offset="0x100600" name="addsigned"/>
<symbol space="ram" offset="0x100700" name="increment"/>
</binaryimage>
<script>
<com>map fun r0x400000 receive</com>
<com>parse line struct myfoo { bool fieldb:1; uint4 field3:3; int4 sfield4:4; char a; char b; char c; int4 d; uint4 field7:7; uint4 field5:5; uint4 field2:2; };</com>
<com>parse line extern void receive(myfoo *ptr);</com>
<com>parse line extern void dosomething(myfoo *ptr,int4 val);</com>
<com>parse line extern int4 doload(myfoo *lp,int4 lval);</com>
<com>parse line extern void dostackinsert(int4 stki_a,uint4 stki_b,uint4 stki_c);</com>
<com>parse line extern int4 docompare(myfoo *ptrcomp);</com>
<com>parse line extern int4 addsigned(myfoo *ap);</com>
<com>parse line extern int4 addsigned(myfoo *ap);</com>
<com>parse line extern void increment(myfoo *ip);</com>
<com>lo fu dosomething</com>
<com>decompile</com>
<com>print C</com>
<com>lo fu doload</com>
<com>decompile</com>
<com>print C</com>
<com>lo fu dostackinsert</com>
<com>decompile</com>
<com>print C</com>
<com>lo fu dostackextract</com>
<com>decompile</com>
<com>print C</com>
<com>lo fu docompare</com>
<com>decompile</com>
<com>print C</com>
<com>lo fu doublecompare</com>
<com>decompile</com>
<com>print C</com>
<com>lo fu addsigned</com>
<com>decompile</com>
<com>print C</com>
<com>lo fu increment</com>
<com>decompile</com>
<com>print C</com>
<com>quit</com>
</script>
<stringmatch name="MIPS Bitfields #1" min="1" max="1">ptr-&gt;field3 = 2;</stringmatch>
<stringmatch name="MIPS Bitfields #2" min="1" max="1">ptr-&gt;sfield4 = val;</stringmatch>
<stringmatch name="MIPS Bitfields #3" min="1" max="1">ptr-&gt;fieldb = val &lt; 10;</stringmatch>
<stringmatch name="MIPS Bitfields #4" min="1" max="1">ptr-&gt;field5 = val \+ 0x14;</stringmatch>
<stringmatch name="MIPS Bitfields #5" min="1" max="1">ptr-&gt;field7 = 100;</stringmatch>
<stringmatch name="MIPS Bitfields #6" min="1" max="1">return lp-&gt;field3;</stringmatch>
<stringmatch name="MIPS Bitfields #7" min="1" max="1">return lp-&gt;field5 \+ lp-&gt;field2;</stringmatch>
<stringmatch name="MIPS Bitfields #8" min="1" max="1">if \(lp-&gt;sfield4 &lt; .*3.*\)</stringmatch>
<stringmatch name="MIPS Bitfields #9" min="1" max="1">return lp-&gt;field2;</stringmatch>
<stringmatch name="MIPS Bitfields #10" min="1" max="1">if \(!+lp-&gt;fieldb\)</stringmatch>
<stringmatch name="MIPS Bitfields #11" min="1" max="1">mStack_18\.sfield4 = \(char\)stki_a \+ .*1.*;</stringmatch>
<stringmatch name="MIPS Bitfields #12" min="1" max="1">mStack_18\.field3 = stki_b;</stringmatch>
<stringmatch name="MIPS Bitfields #13" min="1" max="1">mStack_18\.fieldb = stki_a &lt; 10;</stringmatch>
<stringmatch name="MIPS Bitfields #14" min="1" max="1">mStack_18\.field2 = 1;</stringmatch>
<stringmatch name="MIPS Bitfields #15" min="1" max="1">mStack_18\.field5 = 10;</stringmatch>
<stringmatch name="MIPS Bitfields #16" min="1" max="1">mStack_18\.field7 = stki_c;</stringmatch>
<stringmatch name="MIPS Bitfields #17" min="1" max="1">if \(mStack_18\.fieldb\)</stringmatch>
<stringmatch name="MIPS Bitfields #18" min="1" max="1">uVar1 = mStack_18\.field3 \+ mStack_18\.field5;</stringmatch>
<stringmatch name="MIPS Bitfields #19" min="1" max="1">if \(mStack_18\.sfield4 &lt; '\\0'\)</stringmatch>
<stringmatch name="MIPS Bitfields #20" min="1" max="1">uVar1 = mStack_18\.field2;</stringmatch>
<stringmatch name="MIPS Bitfields #21" min="1" max="1">uVar1 = mStack_18\.field7;</stringmatch>
<stringmatch name="MIPS Bitfields #22" min="1" max="1">ptrcomp-&gt;field3 .= 5\)</stringmatch>
<stringmatch name="MIPS Bitfields #23" min="1" max="1">ptrcomp-&gt;sfield4 .= -3\)</stringmatch>
<stringmatch name="MIPS Bitfields #24" min="1" max="1">ptrcomp-&gt;fieldb\)</stringmatch>
<stringmatch name="MIPS Bitfields #25" min="1" max="1">ptrcomp-&gt;field5 .= 0x1b\)</stringmatch>
<stringmatch name="MIPS Bitfields #26" min="1" max="1">ptrcomp-&gt;field2 .= 0\)</stringmatch>
<stringmatch name="MIPS Bitfields #27" min="1" max="1">ptrcomp-&gt;field7 .= 0x42\)</stringmatch>
<stringmatch name="MIPS Bitfields #28" min="1" max="1">\(mStack_18\.field3 .= 5 .. mStack_18\.sfield4 .= -5\)</stringmatch>
<stringmatch name="MIPS Bitfields #29" min="1" max="1">\(mStack_18\.field7 .= 0x21 .. mStack_18\.field2 .= 0\)</stringmatch>
<stringmatch name="MIPS Bitfields #30" min="1" max="1">return ap-&gt;sfield4 \+ ap-&gt;d;</stringmatch>
<stringmatch name="MIPS Bitfields #31" min="1" max="1">ip-&gt;field5 = ip-&gt;field5 \+ 1;</stringmatch>
</decompilertest>
@@ -39,7 +39,7 @@
plug-in enabled, but if it is disabled for some reason, it can be enabled from within
a Code Browser by selecting the
<informalexample>
<emphasis role="bold">File -> Configure</emphasis>
<emphasis role="bold">File -> Configure...</emphasis>
</informalexample>
menu option, then clicking on the <emphasis>Configure</emphasis> link under the
<emphasis role="bold">Ghidra Core</emphasis> section and checking the box next to
@@ -2059,6 +2059,34 @@
<link linkend="AnalysisSplitStruct">Splitting Structure Accesses</link>.
</para>
</sect4>
<sect4 id="TypeBitField">
<title>Bitfields</title>
<para>
Bitfields are fully supported. Bitfields are a special type of integer field, defined within a structure data-type,
that does not respect byte boundaries. A bitfield can be as small as a single bit, and multiple bitfields can be packed
into a single byte or word of the structure. The Decompiler does not infer bitfields, but propagates them into
the function from structures that explicitly define them.
</para>
<para>
The Decompiler will attempt to display reads and writes to individual bitfields
using the field's name and a standard structure access operator, like '.' or '->'. This hides the
longer sequence of byte-based operations that the underlying code is using to isolate the individual bitfield
from its neighbors.
<informalexample>
<programlisting>
iVar1 = ptr->bit1; // iVar1 = ((*ptr) &gt;&gt; 3) &amp; 7
struct1.bit1 = i; // struct1._0_1 = ((i &amp; 7) &lt;&lt; 3) | (struct1._0_1 &amp; 0xc7)
</programlisting>
</informalexample>
</para>
<para>
If a code sequence sets multiple bitfields simultaneously, the Decompiler will display the sequence
using multiple assignment statements, one for each bitfield affected. If bitfields are read simultaneously, the
Decompiler will display each bitfield as a separate element of the expression. If a code sequence does not seem to respect
the boundaries of individual bitfields, the Decompiler will revert to using auto-generated, byte-based,
field tokens to represent the sequence.
</para>
</sect4>
<sect4 id="TypeEnum">
<title>Enumeration</title>
<para>
@@ -2589,6 +2617,7 @@
<informalexample>
<itemizedlist mark='none'>
<listitem><emphasis>DEFAULT</emphasis> - for basic or no information</listitem>
<listitem><emphasis>AI</emphasis> - for information that is produced with AI assistance</listitem>
<listitem><emphasis>ANALYSIS</emphasis> - for information derived by an Analyzer</listitem>
<listitem><emphasis>IMPORTED</emphasis> - for information imported from an external source</listitem>
<listitem><emphasis>USER_DEFINED</emphasis> - for information set by the user</listitem>
@@ -3054,7 +3083,9 @@
this to <emphasis>off</emphasis> lets the user see the dead code, which is typically demarcated
by the control-flow structure:
<informalexample>
<code>if (false) { ... }</code>
<programlisting>
if (false) { ... }
</programlisting>
</informalexample>
</para>
</listitem>
@@ -3127,7 +3158,9 @@
rendered using a standard <emphasis role="bold">for</emphasis> loop header
that contains an initializer statement, condition, and iterating statement.
<informalexample>
<code>for (iVar2 = 10; iVar2 &lt; len; iVar2 = iVar2 + 1) { ...</code>
<programlisting>
for (iVar2 = 10; iVar2 &lt; len; iVar2 = iVar2 + 1) { ...
</programlisting>
</informalexample>
</para>
<para>
@@ -3158,6 +3191,24 @@
</para>
</listitem>
</varlistentry>
<varlistentry id="AnalysisBitfields">
<term><emphasis role="bold">Simplify bitfield access</emphasis></term>
<listitem>
<para>
When this option is active, the Decompiler attempts to identify expressions where bitfields,
as defined in structure data-types, are either being written to or read from.
Any sequence of logical operations that access an individual bitfield are collapsed into a
normal field access, displaying the bitfield's name.
<informalexample>
<programlisting>
uVar1 = my1._3_1 &lt;&lt; 2 &amp; 3; // Isolating a 2-bit field 'mode' within variable 'my1'
...
uVar1 = my1.mode; // The same assignment after simplification
</programlisting>
</informalexample>
</para>
</listitem>
</varlistentry>
<varlistentry id="AnalysisExtendedPrecision">
<term><emphasis role="bold">Simplify extended integer operations</emphasis></term>
<listitem>
@@ -4962,7 +5013,7 @@
<sect2 id="ActionEditOverride">
<title>Edit Signature Override</title>
<para>
Edit the existing overriding function prototype to the called function under the cursor.
Edit the overriding function prototype applied previously to the called function under the cursor.
</para>
<para>
This action can only be triggered at call sites with an existing signature override. As with the Override
@@ -2,7 +2,7 @@
<article id="pcoderef_title">
<info>
<title>P-Code Reference Manual</title>
<releaseinfo>Last updated March 2, 2023</releaseinfo>
<releaseinfo>Last updated January 16, 2026</releaseinfo>
</info>
<table xml:id="mytoc.htmltable" width="90%" frame='none'>
<col width="25%"/>
@@ -307,7 +307,7 @@ at the destination address.
</para>
<para>
The list of possible
opcodes are similar to many RISC based instruction sets. The effect of
opcodes is similar to many RISC based instruction sets. The effect of
each opcode is described in detail in the following sections,
and a reference table is given
in <xref linkend="reference"/>. In general, the size or
@@ -560,7 +560,7 @@ In this case, the offset of input0 is considered a relative offset into
the indexed list of p-code operations corresponding to the translation
of the current machine instruction. This allows branching within the
operations forming a single instruction. For example, if
the <emphasis role="bold">BRANCH</emphasis> occurs as the pcode
the <emphasis role="bold">BRANCH</emphasis> occurs as the p-code
operation with index 5 for the instruction, it can branch to operation
with index 8 by specifying a constant destination “address” of
3. Negative constants can be used for backward branches.
@@ -3908,26 +3908,29 @@ interpretation as a data-type changes at this point.
</table>
</informalexample>
<para>
The values <emphasis>position</emphasis> and <emphasis>size</emphasis> must be constants.
The least significant <emphasis>size</emphasis> bits from input1 are
inserted into input0, overwriting a range of bits of the same size,
but leaving any other bits in input0 unchanged. The least significant bit of the overwritten
range is given by <emphasis>position</emphasis>, where bits in index0 are labeled from least significant
to most significant, starting at 0. The value obtained after this overwriting is returned
as output.
Varnodes input0 and output must be the same size and are intended to be the same varnode.
The value <emphasis>size</emphasis> must be not be bigger than the varnode input1, and
<emphasis>size</emphasis> + <emphasis>position</emphasis> must not be bigger than the varnode input0.
An <emphasis role="bold">INSERT</emphasis> operation takes the least significant
<emphasis>size</emphasis> bits from input1 and inserts them into input0, overwriting
a range of bits of the same size, but leaving any other bits in input0 unchanged.
</para>
<para>
This operation is never generated as raw p-code, even though it is equivalent
to SLEIGH <emphasis role="bold">bitrange</emphasis> syntax such as input0[10,1] = input1.
The least significant bit of the overwritten range is given by <emphasis>position</emphasis>,
where bits in index0 are labeled from least significant to most significant, starting at 0.
The value obtained after this overwriting is returned
as output. Varnodes input0 and output must be the same size and are intended to be the same
varnode. The values <emphasis>position</emphasis> and <emphasis>size</emphasis> must be
constants. The value <emphasis>size</emphasis> must be not be bigger than the varnode input1,
and <emphasis>size</emphasis> + <emphasis>position</emphasis> must not be bigger than the
varnode input0.
</para>
<para>
This operation is never generated as raw p-code, even though it is equivalent
to SLEIGH <emphasis role="bold">bitrange</emphasis> syntax such as input0[10,1] = input1.
</para>
</sect2>
<sect2 id="cpui_extract"><title>EXTRACT</title>
<sect2 id="cpui_zpull"><title>ZPULL</title>
<informalexample>
<table xml:id="extract.htmltable" frame="above" width="80%" rules="groups">
<table xml:id="zpull.htmltable" frame="above" width="80%" rules="groups">
<col width="23%"/>
<col width="15%"/>
<col width="61%"/>
@@ -3956,7 +3959,7 @@ to SLEIGH <emphasis role="bold">bitrange</emphasis> syntax such as input0[10,1]
<tr>
<td align='right'>output</td>
<td/>
<td>Varnode result containing the extracted value.</td>
<td>Varnode containing the extracted value as an unsigned integer.</td>
</tr>
</tbody>
<tfoot>
@@ -3972,19 +3975,90 @@ to SLEIGH <emphasis role="bold">bitrange</emphasis> syntax such as input0[10,1]
</table>
</informalexample>
<para>
The values <emphasis>position</emphasis> and <emphasis>size</emphasis> must be constants.
The operation extracts <emphasis>size</emphasis> bits from input0 and returns it in output.
The <emphasis>position</emphasis> indicates the least significant bit in the range being extracted, with
the bits in input0 labeled from least to most significant, starting at 0. The varnodes input0 and output
can be different sizes, and the extracted value is zero extended into output.
The value <emphasis>size</emphasis> must not be bigger than the varnode output, and
<emphasis>size</emphasis> + <emphasis>position</emphasis> must not be bigger
than the varnode input0.
A <emphasis role="bold">ZPULL</emphasis> operation extracts <emphasis>size</emphasis> bits
from input0 and returns them as an unsigned integer value in output, zero extending the
bits to the size of output.
</para>
<para>
This operation is never generated as raw p-code, even though it is equivalent
to SLEIGH <emphasis role="bold">bitrange</emphasis> syntax such as output = input0[10,1].
The <emphasis>position</emphasis> indicates the least significant bit in the range
being extracted, with the bits in input0 labeled from least to most significant,
starting at 0. The varnodes input0 and output can be different size.
The values <emphasis>position</emphasis> and <emphasis>size</emphasis> must be constants.
The value <emphasis>size</emphasis> must not be bigger than the varnode output, and
<emphasis>size</emphasis> + <emphasis>position</emphasis> must not be bigger
than the varnode input0.
</para>
<para>
<emphasis role="bold">ZPULL</emphasis> is never generated as raw p-code, even though it
is equivalent to SLEIGH <emphasis role="bold">bitrange</emphasis> syntax such as
output = input0[10,1].
</para>
</sect2>
<sect2 id="cpui_spull"><title>SPULL</title>
<informalexample>
<table xml:id="spull.htmltable" frame="above" width="80%" rules="groups">
<col width="23%"/>
<col width="15%"/>
<col width="61%"/>
<thead>
<tr>
<td align="center" colspan="2"><emphasis role="bold">Parameters</emphasis></td>
<td><emphasis role="bold">Description</emphasis></td>
</tr>
</thead>
<tbody>
<tr>
<td align='right'>input0</td>
<td/>
<td>Varnode to extract a value from.</td>
</tr>
<tr>
<td align='right'>position</td>
<td>(<emphasis role="bold">constant</emphasis>)</td>
<td>Constant indicating the bit position to extract from.</td>
</tr>
<tr>
<td align='right'>size</td>
<td>(<emphasis role="bold">constant</emphasis>)</td>
<td>Constant indicating the number of bits to extract.</td>
</tr>
<tr>
<td align='right'>output</td>
<td/>
<td>Varnode containing the extracted value as a signed integer</td>
</tr>
</tbody>
<tfoot>
<tr>
<td align="center" colspan="2"><emphasis role="bold">Semantic statement</emphasis></td>
<td/>
</tr>
<tr>
<td/>
<td colspan="2"><emphasis>Cannot be explicitly coded.</emphasis></td>
</tr>
</tfoot>
</table>
</informalexample>
<para>
An <emphasis role="bold">SPULL</emphasis> operation extracts <emphasis>size</emphasis> bits
from input0 and returns them as a signed integer value in output. The value is sign extended
to the size of output, duplicating the most significant extracted bit.
</para>
<para>
The <emphasis>position</emphasis> indicates the least significant bit in the range
being extracted, with the bits in input0 labeled from least to most significant,
starting at 0. The varnodes input0 and output can be different size.
The values <emphasis>position</emphasis> and <emphasis>size</emphasis> must be constants.
The value <emphasis>size</emphasis> must not be bigger than the varnode output, and
<emphasis>size</emphasis> + <emphasis>position</emphasis> must not be bigger
than the varnode input0.
</para>
<para>
<emphasis role="bold">SPULL</emphasis> is never generated as raw p-code.
</para>
</sect2>
</sect1>
@@ -4096,7 +4170,7 @@ to SLEIGH <emphasis role="bold">bitrange</emphasis> syntax such as output = inpu
<tr>
<td>SUBPIECE</td>
<td><code>v0:2</code></td>
<td>The least signficant n bytes of v0.</td>
<td>The least significant n bytes of v0.</td>
</tr>
<tr>
<td>SUBPIECE</td>
@@ -677,7 +677,7 @@ define alignment=<emphasis role="bold">integer</emphasis>;
</informalexample>
This specifies the byte alignment of instructions within their address
space. It defaults to 1 or no alignment. When disassembling an
instruction at a particular, the disassembler checks the alignment of
instruction at a particular address, the disassembler checks the alignment of
the address against this value and can opt to flag an unaligned
instruction as an error.
</para>
@@ -837,7 +837,7 @@ Many processors define registers that either consist of a single bit
or otherwise don't use an integral number of bytes. A recurring
example in many processors is the status register which is further
subdivided into the overflow and result flags for the arithmetic
instructions. These flags are typically have labels like ZF for the
instructions. These flags typically have labels like ZF for the
zero flag or CF for the carry flag and can be considered logical
registers contained within the status register. SLEIGH allows
registers to be defined like this using
@@ -1097,10 +1097,10 @@ We list all of the symbols that are predefined by SLEIGH.
</informalexample>
The most important of these to be aware of
are <emphasis>inst_start</emphasis>
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
and <emphasis>inst_next</emphasis>. These are family symbols that map
to the integer offset of either the instruction's address or the next
instruction's address, depending on the context of a particular instruction.
These are used in any relative branching
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>
@@ -1624,7 +1624,7 @@ field.
<title>The '&amp;' and '|' Operators</title>
<para>
More complicated patterns are built out of logical operators. The
meaning of these are fairly straightforward. We can force two or more
meanings of these are fairly straightforward. We can force two or more
constraints to be true at the same time, a <emphasis>logical
and</emphasis> &amp;, or we can require that either one constraint or
another must be true, a <emphasis>logical or</emphasis> |. By using these with
@@ -1933,7 +1933,7 @@ if, when all the variables are evaluated, the equation is true.
<informalexample>
<programlisting>
:xor r1,r2 is opcode=0xcd &amp; r1 &amp; r2 { r1 = r1 ^ r2; }
:clr r1 is opcode=0xcd &amp; r1 &amp; r2=r1 { r1 = 0; }
:clr r1 is opcode=0xcd &amp; r1 &amp; r1=r2 { r1 = 0; }
</programlisting>
</informalexample>
</para>
@@ -1949,10 +1949,10 @@ feature of <emphasis>clr</emphasis> from <emphasis>xor</emphasis> is
that the two fields, specifying the two register inputs
to <emphasis>xor</emphasis>, are equal. The easiest way to specify
this special case is with the general constraint,
<emphasis>r2</emphasis> = <emphasis>r1</emphasis>”, as in the second
<emphasis>r1</emphasis> = <emphasis>r2</emphasis>”, as in the second
line of the example. The SLEIGH compiler will implement this by
enumerating all the cases where <emphasis>r2</emphasis>
equals <emphasis>r1</emphasis>, creating as many states as there are
enumerating all the cases where <emphasis>r1</emphasis>
equals <emphasis>r2</emphasis>, creating as many states as there are
registers. But the specification itself, at least, remains compact.
</para>
</sect3>
@@ -4,7 +4,7 @@
<title>Program Annotations Affecting the Decompiler</title>
<link rel="stylesheet" type="text/css" href="help/shared/DefaultStyle.css">
<link rel="stylesheet" type="text/css" href="../../shared/languages.css">
<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
<meta name="generator" content="DocBook XSL Stylesheets Vsnapshot">
<link rel="home" href="Decompiler.html" title="Decompiler">
<link rel="up" href="Decompiler.html" title="Decompiler">
<link rel="prev" href="DecompilerConcepts.html" title="Decompiler Concepts">
@@ -710,6 +710,38 @@
</div>
<div class="sect4">
<div class="titlepage"><div><div><h5 class="title">
<a name="TypeBitField"></a>Bitfields</h5></div></div></div>
<p>
Bitfields are fully supported. Bitfields are a special type of integer field, defined within a structure data-type,
that does not respect byte boundaries. A bitfield can be as small as a single bit, and multiple bitfields can be packed
into a single byte or word of the structure. The Decompiler does not infer bitfields, but propagates them into
the function from structures that explicitly define them.
</p>
<p>
The Decompiler will attempt to display reads and writes to individual bitfields
using the field's name and a standard structure access operator, like '.' or '-&gt;'. This hides the
longer sequence of byte-based operations that the underlying code is using to isolate the individual bitfield
from its neighbors.
</p>
<div class="informalexample">
<pre class="programlisting">
iVar1 = ptr-&gt;bit1; // iVar1 = ((*ptr) &gt;&gt; 3) &amp; 7
struct1.bit1 = i; // struct1._0_1 = ((i &amp; 7) &lt;&lt; 3) | (struct1._0_1 &amp; 0xc7)
</pre>
</div>
<p>
</p>
<p>
If a code sequence sets multiple bitfields simultaneously, the Decompiler will display the sequence
using multiple assignment statements, one for each bitfield affected. If bitfields are read simultaneously, the
Decompiler will display each bitfield as a separate element of the expression. If a code sequence does not seem to respect
the boundaries of individual bitfields, the Decompiler will revert to using auto-generated, byte-based,
field tokens to represent the sequence.
</p>
</div>
<div class="sect4">
<div class="titlepage"><div><div><h5 class="title">
<a name="TypeEnum"></a>Enumeration</h5></div></div></div>
<p>
@@ -4,7 +4,7 @@
<title>Decompiler Concepts</title>
<link rel="stylesheet" type="text/css" href="help/shared/DefaultStyle.css">
<link rel="stylesheet" type="text/css" href="../../shared/languages.css">
<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
<meta name="generator" content="DocBook XSL Stylesheets Vsnapshot">
<link rel="home" href="Decompiler.html" title="Decompiler">
<link rel="up" href="Decompiler.html" title="Decompiler">
<link rel="prev" href="DecompilerIntro.html" title="Decompiler">
@@ -4,7 +4,7 @@
<title>Decompiler</title>
<link rel="stylesheet" type="text/css" href="help/shared/DefaultStyle.css">
<link rel="stylesheet" type="text/css" href="../../shared/languages.css">
<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
<meta name="generator" content="DocBook XSL Stylesheets Vsnapshot">
<link rel="home" href="Decompiler.html" title="Decompiler">
<link rel="up" href="Decompiler.html" title="Decompiler">
<link rel="prev" href="Decompiler.html" title="Decompiler">
@@ -4,7 +4,7 @@
<title>Decompiler Options</title>
<link rel="stylesheet" type="text/css" href="help/shared/DefaultStyle.css">
<link rel="stylesheet" type="text/css" href="../../shared/languages.css">
<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
<meta name="generator" content="DocBook XSL Stylesheets Vsnapshot">
<link rel="home" href="Decompiler.html" title="Decompiler">
<link rel="up" href="Decompiler.html" title="Decompiler">
<link rel="prev" href="DecompilerAnnotations.html" title="Program Annotations Affecting the Decompiler">
@@ -206,7 +206,9 @@
by the control-flow structure:
</p>
<div class="informalexample">
<code class="code">if (false) { ... }</code>
<pre class="programlisting">
if (false) { ... }
</pre>
</div>
<p>
</p>
@@ -286,7 +288,9 @@
that contains an initializer statement, condition, and iterating statement.
</p>
<div class="informalexample">
<code class="code">for (iVar2 = 10; iVar2 &lt; len; iVar2 = iVar2 + 1) { ...</code>
<pre class="programlisting">
for (iVar2 = 10; iVar2 &lt; len; iVar2 = iVar2 + 1) { ...
</pre>
</div>
<p>
</p>
@@ -318,6 +322,26 @@
</p>
</dd>
<dt>
<a name="AnalysisBitfields"></a><span class="term"><span class="bold"><strong>Simplify bitfield access</strong></span></span>
</dt>
<dd>
<p>
When this option is active, the Decompiler attempts to identify expressions where bitfields,
as defined in structure data-types, are either being written to or read from.
Any sequence of logical operations that access an individual bitfield are collapsed into a
normal field access, displaying the bitfield's name.
</p>
<div class="informalexample">
<pre class="programlisting">
uVar1 = my1._3_1 &lt;&lt; 2 &amp; 3; // Isolating a 2-bit field 'mode' within variable 'my1'
...
uVar1 = my1.mode; // The same assignment after simplification
</pre>
</div>
<p>
</p>
</dd>
<dt>
<a name="AnalysisExtendedPrecision"></a><span class="term"><span class="bold"><strong>Simplify extended integer operations</strong></span></span>
</dt>
<dd>
@@ -534,16 +558,14 @@
(see <a class="xref" href="DecompilerWindow.html#ActionFind" title="Find...">Find...</a>).
</p>
</dd>
<dt>
<a name="MiddleMouseColor"></a><span class="term"><span class="bold"><strong>Color for Highlighting Middle-mouse Matches</strong></span></span>
</dt>
<dd>
<p>
Assign the background color used to highlight characters when highlighting using the middle-mouse button.
</p>
</dd>
<dt>
<a name="MiddleMouseColor"></a><span class="term"><span class="bold"><strong>Color for Highlighting Middle-mouse Matches</strong></span></span>
</dt>
<dd>
<p>
Assign the background color used to highlight characters when highlighting using the middle-mouse button.
</p>
</dd>
<dt>
<a name="DisplayCommentIndent"></a><span class="term"><span class="bold"><strong>Comment line indent level</strong></span></span>
</dt>
@@ -4,7 +4,7 @@
<title>Decompiler Window</title>
<link rel="stylesheet" type="text/css" href="help/shared/DefaultStyle.css">
<link rel="stylesheet" type="text/css" href="../../shared/languages.css">
<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
<meta name="generator" content="DocBook XSL Stylesheets Vsnapshot">
<link rel="home" href="Decompiler.html" title="Decompiler">
<link rel="up" href="Decompiler.html" title="Decompiler">
<link rel="prev" href="DecompilerOptions.html" title="Decompiler Options">
@@ -536,7 +536,6 @@
token, within the Decompiler window. There are actions available from the popup menu and from
the keyboard to navigate to each highlighted token.
</p>
</div>
</div>
@@ -965,10 +964,10 @@
<a name="GoToMiddleMouseHighlight"></a>Go To Next/Previous Highlight</h3></div></div></div>
<p>
These actions are available from the popup menu and keyboard. Only tokens highlighted from the
middle-mouse will be navigated. <span class="bold"><strong>Shift-Comma</strong></span> will
go to the previous highlighted token. <span class="bold"><strong>Shift-Period</strong></span>
will go to the next highlighted token. These key bindings can be changed via the
These actions are available from the popup menu and keyboard. Only tokens highlighted from the
middle-mouse will be navigated. <span class="bold"><strong>Shift-Comma</strong></span> will go to the
previous highlighted token. <span class="bold"><strong>Shift-Period</strong></span> will go to the
next highlighted token. These key bindings can be changed via the
<a class="ulink" href="help/topics/Tool/ToolOptions_Dialog.htm#KeyBindings_Option" target="_top">Tool Options Dialog</a>.
</p>
</div>
@@ -1134,9 +1133,9 @@
Edit the overriding function prototype applied previously to the called function under the cursor.
</p>
<p>
This action can only be triggered at call sites with an existing signature override. As with the Override
Signature command, users must select either the token representing the called function's name or the
tokens representing the function pointer at the call site. The action brings up a dialog where the user
This action can only be triggered at call sites with an existing signature override. As with the Override
Signature command, users must select either the token representing the called function's name or the
tokens representing the function pointer at the call site. The action brings up a dialog where the user
can edit the current overriding function prototype.
</p>
</div>
@@ -0,0 +1,96 @@
/* ###
* 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.decompiler;
import static ghidra.program.model.pcode.AttributeId.*;
import ghidra.program.model.data.*;
import ghidra.program.model.pcode.*;
public class ClangBitFieldToken extends ClangToken {
private Composite dataType; // Structure containing the bitfield
private int ident; // Identifier for the bitfield within its container
private PcodeOp op; // The op associated with the read/write of the field
public ClangBitFieldToken(ClangNode par) {
super(par);
dataType = null;
}
/**
* @return the structure datatype associated with this field token
*/
public DataType getDataType() {
return dataType;
}
/**
* @return the component corresponding to the bitfield if it exists, null otherwise
*/
public DataTypeComponent getComponent() {
if (ident < 0) {
return null;
}
return dataType.getComponent(ident);
}
@Override
public PcodeOp getPcodeOp() {
return op;
}
@Override
public void decode(Decoder decoder, PcodeFactory pfactory) throws DecoderException {
String datatypestring = null;
long id = 0;
ident = -1;
for (;;) {
int attribId = decoder.getNextAttributeId();
if (attribId == 0) {
break;
}
if (attribId == ATTRIB_NAME.id()) { // Name of the structure
datatypestring = decoder.readString();
}
else if (attribId == ATTRIB_ID.id()) {
id = decoder.readUnsignedInteger();
}
else if (attribId == ATTRIB_OPREF.id()) {
int refid = (int) decoder.readUnsignedInteger();
op = pfactory.getOpRef(refid);
}
else if (attribId == ATTRIB_OFF.id()) {
ident = (int) decoder.readSignedInteger();
}
}
if (datatypestring != null) {
DataType dt = pfactory.getDataTypeManager().findBaseType(datatypestring, id);
if (dt == null) {
throw new DecoderException("Cannot find data-type in <bitfield>");
}
if (dt instanceof TypeDef) {
dt = ((TypeDef) dt).getBaseDataType();
}
if (!(dt instanceof Composite)) {
throw new DecoderException("Data-type in <bitfield> is not a composite");
}
dataType = (Composite) dt;
}
decoder.rewindAttributes();
super.decode(decoder, pfactory);
}
}
@@ -4,9 +4,9 @@
* 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.
@@ -259,6 +259,9 @@ public class ClangToken implements ClangNode {
else if (node == ELEM_FIELD.id()) {
token = new ClangFieldToken(par);
}
else if (node == ELEM_BITFIELD.id()) {
token = new ClangBitFieldToken(par);
}
else if (node == ELEM_VALUE.id()) {
token = new ClangCaseToken(par);
}
@@ -202,6 +202,13 @@ public class DecompileOptions {
private final static AliasBlockEnum ALIASBLOCK_OPTIONDEFAULT = AliasBlockEnum.Array; // Must match Architecture::resetDefaultsInternal
private AliasBlockEnum aliasBlock;
private final static String BITFIELD_OPTIONSTRING = "Analysis.Simplify bitfield access";
private final static String BITFIELD_OPTIONDESCRIPTION =
"If set, expressions that insert to or pull from individual bitfields will be displayed " +
"as a normal member field access.";
private final static boolean BITFIELD_OPTIONDEFAULT = true;
private boolean bitfieldAccess;
private final static String CONVENTION_OPTIONSTRING = "Display.Print calling convention name";
private final static String CONVENTION_OPTIONDESCRIPTION =
"If set, the names of calling conventions (when they differ " +
@@ -499,6 +506,7 @@ public class DecompileOptions {
nullToken = NULLTOKEN_OPTIONDEFAULT;
inplaceTokens = INPLACEOP_OPTIONDEFAULT;
aliasBlock = ALIASBLOCK_OPTIONDEFAULT;
bitfieldAccess = BITFIELD_OPTIONDEFAULT;
conventionPrint = CONVENTION_OPTIONDEFAULT;
noCastPrint = NOCAST_OPTIONDEFAULT;
braceFunction = BRACEFUNCTION_OPTIONDEFAULT;
@@ -563,6 +571,7 @@ public class DecompileOptions {
nullToken = opt.getBoolean(NULLTOKEN_OPTIONSTRING, NULLTOKEN_OPTIONDEFAULT);
inplaceTokens = opt.getBoolean(INPLACEOP_OPTIONSTRING, INPLACEOP_OPTIONDEFAULT);
aliasBlock = opt.getEnum(ALIASBLOCK_OPTIONSTRING, ALIASBLOCK_OPTIONDEFAULT);
bitfieldAccess = opt.getBoolean(BITFIELD_OPTIONSTRING, BITFIELD_OPTIONDEFAULT);
conventionPrint = opt.getBoolean(CONVENTION_OPTIONSTRING, CONVENTION_OPTIONDEFAULT);
noCastPrint = opt.getBoolean(NOCAST_OPTIONSTRING, NOCAST_OPTIONDEFAULT);
braceFunction = opt.getEnum(BRACEFUNCTION_OPTIONSTRING, BRACEFUNCTION_OPTIONDEFAULT);
@@ -693,6 +702,9 @@ public class DecompileOptions {
opt.registerOption(ALIASBLOCK_OPTIONSTRING, ALIASBLOCK_OPTIONDEFAULT,
new HelpLocation(HelpTopics.DECOMPILER, "AnalysisAliasBlocking"),
ALIASBLOCK_OPTIONDESCRIPTION);
opt.registerOption(BITFIELD_OPTIONSTRING, BITFIELD_OPTIONDEFAULT,
new HelpLocation(HelpTopics.DECOMPILER, "AnalysisBitfields"),
BITFIELD_OPTIONDESCRIPTION);
opt.registerOption(CONVENTION_OPTIONSTRING, CONVENTION_OPTIONDEFAULT,
new HelpLocation(HelpTopics.DECOMPILER, "DisplayConvention"),
CONVENTION_OPTIONDESCRIPTION);
@@ -892,6 +904,10 @@ public class DecompileOptions {
if (aliasBlock != ALIASBLOCK_OPTIONDEFAULT) {
appendOption(encoder, ELEM_ALIASBLOCK, aliasBlock.getOptionString(), "", "");
}
if (bitfieldAccess != BITFIELD_OPTIONDEFAULT) {
appendOption(encoder, ELEM_CURRENTACTION, "bitfields", bitfieldAccess ? "on" : "off",
"");
}
if (conventionPrint != CONVENTION_OPTIONDEFAULT) {
appendOption(encoder, ELEM_CONVENTIONPRINTING, conventionPrint ? "on" : "off", "", "");
}
@@ -1664,6 +1680,22 @@ public class DecompileOptions {
this.aliasBlock = aliasBlock;
}
/**
* {@return true if expressions accessing bitfields are simplified.}
* @see #BITFIELD_OPTIONDESCRIPTION
*/
public boolean isBitfieldAccess() {
return bitfieldAccess;
}
/**
* Set whether expressions accessing bitfields are simplified.
* @param bitfield true to enable simplification of expressions
*/
public void setBitfieldAccess(boolean bitfield) {
this.bitfieldAccess = bitfield;
}
/**
* {@return number of characters per indent level.}
*/
@@ -950,6 +950,9 @@ public class DecompilerProvider extends NavigatableComponentProviderAdapter
RenameFieldAction renameFieldAction = new RenameFieldAction();
setGroupInfo(renameFieldAction, variableGroup, subGroupPosition++);
RenameBitFieldAction renameBitFieldAction = new RenameBitFieldAction();
setGroupInfo(renameBitFieldAction, variableGroup, subGroupPosition++);
ForceUnionAction forceUnionAction = new ForceUnionAction();
setGroupInfo(forceUnionAction, variableGroup, subGroupPosition++);
@@ -1148,6 +1151,7 @@ public class DecompilerProvider extends NavigatableComponentProviderAdapter
addLocalAction(renameLocalAction);
addLocalAction(renameGlobalAction);
addLocalAction(renameFieldAction);
addLocalAction(renameBitFieldAction);
addLocalAction(forceUnionAction);
addLocalAction(setSecondaryHighlightAction);
addLocalAction(setSecondaryHighlightColorChooserAction);
@@ -0,0 +1,61 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.plugin.core.decompile.actions;
import java.awt.event.KeyEvent;
import docking.action.KeyBindingData;
import docking.action.MenuData;
import ghidra.app.decompiler.ClangBitFieldToken;
import ghidra.app.decompiler.ClangToken;
import ghidra.app.plugin.core.decompile.DecompilerActionContext;
import ghidra.app.util.HelpTopics;
import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.listing.Function;
import ghidra.util.HelpLocation;
import ghidra.util.UndefinedFunction;
public class RenameBitFieldAction extends AbstractDecompilerAction {
public RenameBitFieldAction() {
super("Rename BitField");
setHelpLocation(new HelpLocation(HelpTopics.DECOMPILER, "ActionRenameField"));
setPopupMenuData(new MenuData(new String[] { "Rename BitField" }, "Decompile"));
setKeyBindingData(new KeyBindingData(KeyEvent.VK_L, 0));
}
@Override
protected boolean isEnabledForDecompilerContext(DecompilerActionContext context) {
Function function = context.getFunction();
if (function == null || function instanceof UndefinedFunction) {
return false;
}
ClangToken tokenAtCursor = context.getTokenAtCursor();
return (tokenAtCursor instanceof ClangBitFieldToken);
}
@Override
protected void decompilerActionPerformed(DecompilerActionContext context) {
PluginTool tool = context.getTool();
ClangBitFieldToken tokenAtCursor = (ClangBitFieldToken) context.getTokenAtCursor();
RenameTask nameTask = new RenameStructBitFieldTask(tool, context.getProgram(),
context.getComponentProvider(), tokenAtCursor);
nameTask.runTask(true);
}
}
@@ -0,0 +1,69 @@
/* ###
* 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.core.decompile.actions;
import ghidra.app.decompiler.ClangBitFieldToken;
import ghidra.app.plugin.core.decompile.DecompilerProvider;
import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.data.Composite;
import ghidra.program.model.data.DataTypeComponent;
import ghidra.program.model.listing.Program;
import ghidra.util.exception.DuplicateNameException;
import ghidra.util.exception.InvalidInputException;
public class RenameStructBitFieldTask extends RenameTask {
private ClangBitFieldToken token;
private DataTypeComponent component;
public RenameStructBitFieldTask(PluginTool tool, Program program, DecompilerProvider provider,
ClangBitFieldToken token) {
super(tool, program, provider, token, token.getText());
this.token = token;
}
@Override
public String getTransactionName() {
return "Rename Structure BitField";
}
@Override
public boolean isValid(String newNm) {
newName = newNm;
component = token.getComponent();
if (component == null) {
return false;
}
Composite structure = (Composite) token.getDataType();
DataTypeComponent[] comp = structure.getDefinedComponents();
for (DataTypeComponent element : comp) {
String fieldname = element.getFieldName();
if (fieldname == null) {
continue;
}
if (fieldname.equals(newName)) {
errorMsg = "Duplicate Field Name";
return false;
}
}
return true;
}
@Override
public void commit() throws DuplicateNameException, InvalidInputException {
component.setFieldName(newName);
}
}
@@ -4,9 +4,9 @@
* 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.
@@ -102,9 +102,10 @@ public class OpBehaviorFactory {
opBehaviorMap.put(PcodeOp.CPOOLREF, new SpecialOpBehavior(PcodeOp.CPOOLREF));
opBehaviorMap.put(PcodeOp.NEW, new SpecialOpBehavior(PcodeOp.NEW));
opBehaviorMap.put(PcodeOp.INSERT, new SpecialOpBehavior(PcodeOp.INSERT));
opBehaviorMap.put(PcodeOp.EXTRACT, new SpecialOpBehavior(PcodeOp.EXTRACT));
opBehaviorMap.put(PcodeOp.ZPULL, new SpecialOpBehavior(PcodeOp.ZPULL));
opBehaviorMap.put(PcodeOp.POPCOUNT, new OpBehaviorPopcount());
opBehaviorMap.put(PcodeOp.LZCOUNT, new OpBehaviorLzcount());
opBehaviorMap.put(PcodeOp.SPULL, new SpecialOpBehavior(PcodeOp.SPULL));
}
private OpBehaviorFactory() {

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