mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-05-22 21:18:32 +08:00
GP-2493 Bitfield support in the Decompiler
This commit is contained in:
@@ -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 ©,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->field3 = 2;</stringmatch>
|
||||
<stringmatch name="Bitfields #2" min="1" max="1">ptr->fieldb = val < 10;</stringmatch>
|
||||
<stringmatch name="Bitfields #3" min="1" max="1">ptr->sfield4 = val;</stringmatch>
|
||||
<stringmatch name="Bitfields #4" min="1" max="1">ptr->field5 = \(uint1\)val \+ 0x14;</stringmatch>
|
||||
<stringmatch name="Bitfields #5" min="1" max="1">ptr->field7 = 100;</stringmatch>
|
||||
<stringmatch name="Bitfields #6" min="1" max="1">return loadptr->field3;</stringmatch>
|
||||
<stringmatch name="Bitfields #7" min="1" max="1">if \(.*2.* < loadptr->sfield4\)</stringmatch>
|
||||
<stringmatch name="Bitfields #8" min="1" max="1">-\(uint4\)!loadptr->fieldb & 900</stringmatch>
|
||||
<stringmatch name="Bitfields #9" min="1" max="1">return loadptr->field2;</stringmatch>
|
||||
<stringmatch name="Bitfields #10" min="1" max="1">return loadptr->field5 \+ loadptr->field2;</stringmatch>
|
||||
<stringmatch name="Bitfields #11" min="1" max="1">mStack_14\.fieldb = stki_a < 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 < 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->field3 .= 5\)</stringmatch>
|
||||
<stringmatch name="Bitfields #23" min="1" max="1">ptrcomp->sfield4 .= -3\)</stringmatch>
|
||||
<stringmatch name="Bitfields #24" min="1" max="1">ptrcomp->fieldb\)</stringmatch>
|
||||
<stringmatch name="Bitfields #25" min="1" max="1">ptrcomp->field5 .= 0x1b\)</stringmatch>
|
||||
<stringmatch name="Bitfields #26" min="1" max="1">ptrcomp->field2 .= 0\)</stringmatch>
|
||||
<stringmatch name="Bitfields #27" min="1" max="1">ptrcomp->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->sfield4 \+ ap->d;</stringmatch>
|
||||
<stringmatch name="Bitfields #31" min="1" max="1">ip->field5 = ip->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->field3 = 2;</stringmatch>
|
||||
<stringmatch name="MIPS Bitfields #2" min="1" max="1">ptr->sfield4 = val;</stringmatch>
|
||||
<stringmatch name="MIPS Bitfields #3" min="1" max="1">ptr->fieldb = val < 10;</stringmatch>
|
||||
<stringmatch name="MIPS Bitfields #4" min="1" max="1">ptr->field5 = val \+ 0x14;</stringmatch>
|
||||
<stringmatch name="MIPS Bitfields #5" min="1" max="1">ptr->field7 = 100;</stringmatch>
|
||||
<stringmatch name="MIPS Bitfields #6" min="1" max="1">return lp->field3;</stringmatch>
|
||||
<stringmatch name="MIPS Bitfields #7" min="1" max="1">return lp->field5 \+ lp->field2;</stringmatch>
|
||||
<stringmatch name="MIPS Bitfields #8" min="1" max="1">if \(lp->sfield4 < .*3.*\)</stringmatch>
|
||||
<stringmatch name="MIPS Bitfields #9" min="1" max="1">return lp->field2;</stringmatch>
|
||||
<stringmatch name="MIPS Bitfields #10" min="1" max="1">if \(!+lp->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 < 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 < '\\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->field3 .= 5\)</stringmatch>
|
||||
<stringmatch name="MIPS Bitfields #23" min="1" max="1">ptrcomp->sfield4 .= -3\)</stringmatch>
|
||||
<stringmatch name="MIPS Bitfields #24" min="1" max="1">ptrcomp->fieldb\)</stringmatch>
|
||||
<stringmatch name="MIPS Bitfields #25" min="1" max="1">ptrcomp->field5 .= 0x1b\)</stringmatch>
|
||||
<stringmatch name="MIPS Bitfields #26" min="1" max="1">ptrcomp->field2 .= 0\)</stringmatch>
|
||||
<stringmatch name="MIPS Bitfields #27" min="1" max="1">ptrcomp->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->sfield4 \+ ap->d;</stringmatch>
|
||||
<stringmatch name="MIPS Bitfields #31" min="1" max="1">ip->field5 = ip->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) >> 3) & 7
|
||||
struct1.bit1 = i; // struct1._0_1 = ((i & 7) << 3) | (struct1._0_1 & 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 < len; iVar2 = iVar2 + 1) { ...</code>
|
||||
<programlisting>
|
||||
for (iVar2 = 10; iVar2 < 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 << 2 & 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 '&' 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> ‘&’, 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 & r1 & r2 { r1 = r1 ^ r2; }
|
||||
:clr r1 is opcode=0xcd & r1 & r2=r1 { r1 = 0; }
|
||||
:clr r1 is opcode=0xcd & r1 & 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>
|
||||
|
||||
+33
-1
@@ -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 '->'. 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->bit1; // iVar1 = ((*ptr) >> 3) & 7
|
||||
struct1.bit1 = i; // struct1._0_1 = ((i & 7) << 3) | (struct1._0_1 & 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>
|
||||
|
||||
+1
-1
@@ -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">
|
||||
|
||||
+1
-1
@@ -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">
|
||||
|
||||
+35
-13
@@ -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 < len; iVar2 = iVar2 + 1) { ...</code>
|
||||
<pre class="programlisting">
|
||||
for (iVar2 = 10; iVar2 < 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 << 2 & 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>
|
||||
|
||||
+8
-9
@@ -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>
|
||||
|
||||
+96
@@ -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.}
|
||||
*/
|
||||
|
||||
+4
@@ -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);
|
||||
|
||||
+61
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
+69
@@ -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
-3
@@ -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
Reference in New Issue
Block a user