mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-06-02 16:18:20 +08:00
GP-2493 Bitfield support in the Decompiler
This commit is contained in:
@@ -105,6 +105,7 @@ model {
|
|||||||
include "merge.cc"
|
include "merge.cc"
|
||||||
include "double.cc"
|
include "double.cc"
|
||||||
include "constseq.cc"
|
include "constseq.cc"
|
||||||
|
include "bitfield.cc"
|
||||||
include "coreaction.cc"
|
include "coreaction.cc"
|
||||||
include "condexe.cc"
|
include "condexe.cc"
|
||||||
include "override.cc"
|
include "override.cc"
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ src/decompile/.cproject||GHIDRA||||END|
|
|||||||
src/decompile/cpp/.gitignore||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/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/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/boolless.xml||GHIDRA||||END|
|
||||||
src/decompile/datatests/ccmp.xml||GHIDRA||||END|
|
src/decompile/datatests/ccmp.xml||GHIDRA||||END|
|
||||||
src/decompile/datatests/concat.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 \
|
variable varmap jumptable emulate emulateutil flow userop expression multiprecision \
|
||||||
funcdata funcdata_block funcdata_op funcdata_varnode unionresolve pcodeinject \
|
funcdata funcdata_block funcdata_op funcdata_varnode unionresolve pcodeinject \
|
||||||
heritage prefersplit rangeutil ruleaction subflow blockaction merge double \
|
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)
|
printlanguage printc printjava memstate opbehavior paramid signature $(COREEXT_NAMES)
|
||||||
# Files used for any project that use the sleigh decoder
|
# Files used for any project that use the sleigh decoder
|
||||||
SLEIGH= sleigh pcodeparse pcodecompile sleighbase slghsymbol \
|
SLEIGH= sleigh pcodeparse pcodecompile sleighbase slghsymbol \
|
||||||
|
|||||||
@@ -627,6 +627,246 @@ void RangeList::decode(Decoder &decoder)
|
|||||||
decoder.closeElement(elemId);
|
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
|
#ifdef UINTB4
|
||||||
uintb uintbmasks[9] = { 0, 0xff, 0xffff, 0xffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff };
|
uintb uintbmasks[9] = { 0, 0xff, 0xffff, 0xffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff };
|
||||||
#else
|
#else
|
||||||
@@ -675,6 +915,22 @@ uintb sign_extend(uintb in,int4 sizein,int4 sizeout)
|
|||||||
return res;
|
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
|
/// Swap the least significant \b size bytes in \b val
|
||||||
/// \param val is a reference to the value to swap
|
/// \param val is a reference to the value to swap
|
||||||
/// \param size is the number of bytes 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
|
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
|
/// Precalculated masks indexed by size
|
||||||
extern uintb uintbmasks[];
|
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 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 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 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
|
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;
|
if (!copyRoot->isWritten()) break;
|
||||||
op = copyRoot->getDef();
|
op = copyRoot->getDef();
|
||||||
opc = op->code();
|
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;
|
break;
|
||||||
} while(op->getIn(1)->isConstant());
|
} while(op->getIn(1)->isConstant());
|
||||||
|
|
||||||
@@ -523,7 +523,7 @@ void HeapSequence::findDuplicateBases(vector<Varnode *> &duplist)
|
|||||||
op = *iter;
|
op = *iter;
|
||||||
++iter;
|
++iter;
|
||||||
opc = op->code();
|
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;
|
continue;
|
||||||
if (op->getIn(0) != vn || !op->getIn(1)->isConstant())
|
if (op->getIn(0) != vn || !op->getIn(1)->isConstant())
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
#include "double.hh"
|
#include "double.hh"
|
||||||
#include "subflow.hh"
|
#include "subflow.hh"
|
||||||
#include "constseq.hh"
|
#include "constseq.hh"
|
||||||
|
#include "bitfield.hh"
|
||||||
|
|
||||||
namespace ghidra {
|
namespace ghidra {
|
||||||
|
|
||||||
@@ -1540,7 +1541,7 @@ void ActionFuncLink::funcLinkOutput(FuncCallSpecs *fc,Funcdata &data)
|
|||||||
Datatype *outtype = outparam->getType();
|
Datatype *outtype = outparam->getType();
|
||||||
if (outtype->getMetatype() != TYPE_VOID) {
|
if (outtype->getMetatype() != TYPE_VOID) {
|
||||||
int4 sz = outparam->getSize();
|
int4 sz = outparam->getSize();
|
||||||
if (sz == 1 && outtype->getMetatype() == TYPE_BOOL && data.isTypeRecoveryOn())
|
if (outtype->getMetatype() == TYPE_BOOL && data.isTypeRecoveryOn())
|
||||||
data.opMarkCalculatedBool(callop);
|
data.opMarkCalculatedBool(callop);
|
||||||
Address addr = outparam->getAddress();
|
Address addr = outparam->getAddress();
|
||||||
if (addr.getSpace()->getType() == IPTR_SPACEBASE) {
|
if (addr.getSpace()->getType() == IPTR_SPACEBASE) {
|
||||||
@@ -2349,6 +2350,7 @@ int4 ActionDefaultParams::apply(Funcdata &data)
|
|||||||
void ActionSetCasts::checkPointerIssues(PcodeOp *op,Varnode *vn,Funcdata &data)
|
void ActionSetCasts::checkPointerIssues(PcodeOp *op,Varnode *vn,Funcdata &data)
|
||||||
|
|
||||||
{
|
{
|
||||||
|
if (op->doesSpecialPrinting()) return;
|
||||||
Datatype *ptrtype = op->getIn(1)->getHighTypeReadFacing(op);
|
Datatype *ptrtype = op->getIn(1)->getHighTypeReadFacing(op);
|
||||||
int4 valsize = vn->getSize();
|
int4 valsize = vn->getSize();
|
||||||
if ((ptrtype->getMetatype()!=TYPE_PTR)|| (((TypePointer *)ptrtype)->getPtrTo()->getSize() != valsize)) {
|
if ((ptrtype->getMetatype()!=TYPE_PTR)|| (((TypePointer *)ptrtype)->getPtrTo()->getSize() != valsize)) {
|
||||||
@@ -3062,6 +3064,11 @@ int4 ActionMarkExplicit::baseExplicit(Varnode *vn,int4 maxref)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (vn->hasNoDescend()) return -1; // Must have at least one descendant
|
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
|
if (def->code() == CPUI_PTRSUB) { // A dereference
|
||||||
Varnode *basevn = def->getIn(0);
|
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 (sz > sizeof(uintb)) { // If there exists bits beyond the precision of the consume field
|
||||||
if (sa >= 8*sizeof(uintb))
|
if (sa >= 8*sizeof(uintb))
|
||||||
a = ~((uintb)0); // Make sure we assume one bits where we shift in unrepresented bits
|
a = ~((uintb)0); // Make sure we assume one bits where we shift in unrepresented bits
|
||||||
|
else if (sa == 0) {
|
||||||
|
a = outc;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
a = (outc >> sa) ^ ( (~((uintb)0)) << (8*sizeof(uintb)-sa));
|
a = (outc >> sa) ^ ( (~((uintb)0)) << (8*sizeof(uintb)-sa));
|
||||||
sz = 8*sz -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(2), worklist);
|
||||||
pushConsumed(b,op->getIn(3), worklist);
|
pushConsumed(b,op->getIn(3), worklist);
|
||||||
break;
|
break;
|
||||||
case CPUI_EXTRACT:
|
case CPUI_ZPULL:
|
||||||
|
case CPUI_SPULL:
|
||||||
a = 1;
|
a = 1;
|
||||||
a <<= (int4)op->getIn(2)->getOffset();
|
a <<= (int4)op->getIn(2)->getOffset();
|
||||||
a -= 1; // Extract mask
|
a -= 1; // Pull mask
|
||||||
a &= outc; // Consumed bits of mask
|
a &= outc; // Consumed bits of mask
|
||||||
a <<= (int4)op->getIn(1)->getOffset();
|
a <<= (int4)op->getIn(1)->getOffset();
|
||||||
pushConsumed(a,op->getIn(0),worklist);
|
pushConsumed(a,op->getIn(0),worklist);
|
||||||
@@ -5425,7 +5436,7 @@ void ActionDatabase::buildDefaultGroups(void)
|
|||||||
"deadcode", "typerecovery", "stackptrflow",
|
"deadcode", "typerecovery", "stackptrflow",
|
||||||
"blockrecovery", "stackvars", "deadcontrolflow", "switchnorm",
|
"blockrecovery", "stackvars", "deadcontrolflow", "switchnorm",
|
||||||
"cleanup", "splitcopy", "splitpointer", "merge", "dynamic", "casts", "analysis",
|
"cleanup", "splitcopy", "splitpointer", "merge", "dynamic", "casts", "analysis",
|
||||||
"fixateglobals", "fixateproto", "constsequence",
|
"fixateglobals", "fixateproto", "constsequence", "bitfields",
|
||||||
"segment", "returnsplit", "nodejoin", "doubleload", "doubleprecis",
|
"segment", "returnsplit", "nodejoin", "doubleload", "doubleprecis",
|
||||||
"unreachable", "subvar", "floatprecision",
|
"unreachable", "subvar", "floatprecision",
|
||||||
"conditionalexe", "" };
|
"conditionalexe", "" };
|
||||||
@@ -5708,6 +5719,12 @@ void ActionDatabase::universalAction(Architecture *conf)
|
|||||||
actcleanup->addRule( new RuleSplitStore("splitpointer") );
|
actcleanup->addRule( new RuleSplitStore("splitpointer") );
|
||||||
actcleanup->addRule( new RuleStringCopy("constsequence"));
|
actcleanup->addRule( new RuleStringCopy("constsequence"));
|
||||||
actcleanup->addRule( new RuleStringStore("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 );
|
act->addAction( actcleanup );
|
||||||
|
|
||||||
|
|||||||
@@ -57,8 +57,8 @@ const uint4 DynamicHash::transtable[] = {
|
|||||||
|
|
||||||
0, // CAST is skipped
|
0, // CAST is skipped
|
||||||
CPUI_INT_ADD, CPUI_INT_ADD, // PTRADD and PTRSUB hash same as INT_ADD
|
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_SEGMENTOP, CPUI_CPOOLREF, CPUI_NEW, CPUI_INSERT, CPUI_ZPULL,
|
||||||
CPUI_POPCOUNT, CPUI_LZCOUNT
|
CPUI_POPCOUNT, CPUI_LZCOUNT, CPUI_SPULL
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
#include "expression.hh"
|
#include "expression.hh"
|
||||||
|
#include "database.hh"
|
||||||
|
|
||||||
namespace ghidra {
|
namespace ghidra {
|
||||||
|
|
||||||
@@ -392,6 +393,198 @@ void AddExpression::gatherTwoTermsRoot(Varnode *root)
|
|||||||
gather(root,(uintb)1,1);
|
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
|
/// \brief Perform basic comparison of two given Varnodes
|
||||||
///
|
///
|
||||||
/// Return
|
/// Return
|
||||||
@@ -559,4 +752,53 @@ bool functionalDifference(Varnode *vn1,Varnode *vn2,int4 depth)
|
|||||||
return false;
|
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
|
} // End namespace ghidra
|
||||||
|
|||||||
@@ -134,6 +134,17 @@ public:
|
|||||||
const vector<AdditiveEdge *> &getSort(void) { return sorter; } ///< Get the sorted list of references
|
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
|
/// \brief Class for lightweight matching of two additive expressions
|
||||||
///
|
///
|
||||||
/// Collect (up to 2) terms along with any constants and coefficients.
|
/// 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
|
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
|
/// The expression centers around either a CPUI_INSERT or a CPUI_EXTRACT op but encompasses multiple p-code ops
|
||||||
/// ignores multiplicative coefficients.
|
/// that represent either a single read of or single write to a bitfield within a structure. This class recovers
|
||||||
/// \param op1 is the first term to compare
|
/// the expected elements of the expression. The method isValid() returns \b true if the expression has the
|
||||||
/// \param op2 is the second term
|
/// expected form and can be interpreted as a single read or write.
|
||||||
/// \return \b true if the first term is less than the second
|
class BitFieldExpression {
|
||||||
inline bool TermOrder::additiveCompare(const AdditiveEdge *op1,const AdditiveEdge *op2) {
|
protected:
|
||||||
return (-1 == op1->getVarnode()->termOrder(op2->getVarnode()));
|
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 int4 functionalEqualityLevel(Varnode *vn1,Varnode *vn2,Varnode **res1,Varnode **res2);
|
||||||
extern bool functionalEquality(Varnode *vn1,Varnode *vn2);
|
extern bool functionalEquality(Varnode *vn1,Varnode *vn2);
|
||||||
extern bool functionalDifference(Varnode *vn1,Varnode *vn2,int4 depth);
|
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
|
} // End namespace ghidra
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -292,6 +292,7 @@ public:
|
|||||||
Varnode *newExtendedConstant(int4 s,uint8 *val,PcodeOp *op); ///< Create extended precision constant
|
Varnode *newExtendedConstant(int4 s,uint8 *val,PcodeOp *op); ///< Create extended precision constant
|
||||||
void adjustInputVarnodes(const Address &addr,int4 sz);
|
void adjustInputVarnodes(const Address &addr,int4 sz);
|
||||||
void deleteVarnode(Varnode *vn) { vbank.destroy(vn); } ///< Delete the given varnode
|
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
|
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
|
/// All p-code ops that read the Varnode are transformed so that they read
|
||||||
/// a special constant instead (associate with unreachable block removal).
|
/// a special constant instead (associate with unreachable block removal).
|
||||||
/// \param vn is the given Varnode
|
/// \param vn is the given Varnode
|
||||||
@@ -888,6 +904,9 @@ void Funcdata::calcNZMask(void)
|
|||||||
if (!vn->isWritten()) {
|
if (!vn->isWritten()) {
|
||||||
if (vn->isConstant())
|
if (vn->isConstant())
|
||||||
vn->nzm = vn->getOffset();
|
vn->nzm = vn->getOffset();
|
||||||
|
else if (vn->isTypeLock() && vn->getType()->getMetatype() == TYPE_BOOL) {
|
||||||
|
vn->nzm = 1;
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
vn->nzm = calc_mask(vn->getSize());
|
vn->nzm = calc_mask(vn->getSize());
|
||||||
if (vn->isSpacebase())
|
if (vn->isSpacebase())
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -37,11 +37,12 @@ public:
|
|||||||
badtoken = 0x100,
|
badtoken = 0x100,
|
||||||
endoffile = 0x101,
|
endoffile = 0x101,
|
||||||
dotdotdot = 0x102,
|
dotdotdot = 0x102,
|
||||||
|
scoperes = 0x103,
|
||||||
|
|
||||||
integer = 0x103,
|
integer = 0x104,
|
||||||
charconstant = 0x104,
|
charconstant = 0x105,
|
||||||
identifier = 0x105,
|
identifier = 0x106,
|
||||||
stringval = 0x106,
|
stringval = 0x107,
|
||||||
};
|
};
|
||||||
private:
|
private:
|
||||||
uint4 type;
|
uint4 type;
|
||||||
@@ -85,6 +86,8 @@ class GrammarLexer {
|
|||||||
dot1,
|
dot1,
|
||||||
dot2,
|
dot2,
|
||||||
dot3,
|
dot3,
|
||||||
|
scoperes1,
|
||||||
|
scoperes2,
|
||||||
punctuation,
|
punctuation,
|
||||||
endofline_comment,
|
endofline_comment,
|
||||||
c_comment,
|
c_comment,
|
||||||
@@ -169,12 +172,15 @@ class TypeDeclarator {
|
|||||||
string ident; // variable identifier associated with type
|
string ident; // variable identifier associated with type
|
||||||
string model; // name of model associated with function pointer
|
string model; // name of model associated with function pointer
|
||||||
uint4 flags; // Specifiers qualifiers
|
uint4 flags; // Specifiers qualifiers
|
||||||
|
int4 numBits; // Number of bits associated with declaration (0=unspecified)
|
||||||
public:
|
public:
|
||||||
TypeDeclarator(void) { 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; }
|
TypeDeclarator(const string &nm) { ident=nm; basetype=(Datatype *)0; flags=0; numBits=0; }
|
||||||
~TypeDeclarator(void);
|
~TypeDeclarator(void);
|
||||||
Datatype *getBaseType(void) const { return basetype; }
|
Datatype *getBaseType(void) const { return basetype; }
|
||||||
int4 numModifiers(void) const { return mods.size(); }
|
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; }
|
const string &getIdentifier(void) const { return ident; }
|
||||||
ProtoModel *getModel(Architecture *glb) const;
|
ProtoModel *getModel(Architecture *glb) const;
|
||||||
bool getPrototype(PrototypePieces &pieces,Architecture *glb) const;
|
bool getPrototype(PrototypePieces &pieces,Architecture *glb) const;
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ static CParse *parse;
|
|||||||
|
|
||||||
// Grammar taken from ISO/IEC 9899
|
// 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 <i> NUMBER
|
||||||
%token <str> IDENTIFIER
|
%token <str> IDENTIFIER
|
||||||
%token <str> STORAGE_CLASS_SPECIFIER TYPE_QUALIFIER FUNCTION_SPECIFIER
|
%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 <type> type_specifier struct_or_union_specifier enum_specifier
|
||||||
%type <enumer> enumerator
|
%type <enumer> enumerator
|
||||||
%type <vecenum> enumerator_list
|
%type <vecenum> enumerator_list
|
||||||
|
%type <str> var_identifier
|
||||||
%%
|
%%
|
||||||
|
|
||||||
document:
|
document:
|
||||||
@@ -127,7 +128,7 @@ struct_declarator_list:
|
|||||||
|
|
||||||
struct_declarator:
|
struct_declarator:
|
||||||
declarator { $$ = $1; }
|
declarator { $$ = $1; }
|
||||||
// declarator ':' NUMBER
|
| declarator ':' NUMBER { $$ = $1; $1->setNumBits((int4)*$3); }
|
||||||
;
|
;
|
||||||
|
|
||||||
enum_specifier:
|
enum_specifier:
|
||||||
@@ -153,8 +154,13 @@ declarator:
|
|||||||
| pointer direct_declarator { $$ = parse->mergePointer($1,$2); }
|
| pointer direct_declarator { $$ = parse->mergePointer($1,$2); }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
var_identifier:
|
||||||
|
IDENTIFIER { $$ = $1; }
|
||||||
|
| var_identifier SCOPERES IDENTIFIER { $$ = $1; $$->append("::"); $$->append(*$3); }
|
||||||
|
;
|
||||||
|
|
||||||
direct_declarator:
|
direct_declarator:
|
||||||
IDENTIFIER { $$ = parse->newDeclarator($1); }
|
var_identifier { $$ = parse->newDeclarator($1); }
|
||||||
| '(' declarator ')' { $$ = $2; }
|
| '(' declarator ')' { $$ = $2; }
|
||||||
| direct_declarator '[' type_qualifier_list assignment_expression ']' { $$ = parse->newArray($1,$3,$4); }
|
| direct_declarator '[' type_qualifier_list assignment_expression ']' { $$ = parse->newArray($1,$3,$4); }
|
||||||
| direct_declarator '[' assignment_expression ']' { $$ = parse->newArray($1,0,$3); }
|
| direct_declarator '[' assignment_expression ']' { $$ = parse->newArray($1,0,$3); }
|
||||||
@@ -361,6 +367,9 @@ uint4 GrammarLexer::moveState(char lookahead)
|
|||||||
state = punctuation;
|
state = punctuation;
|
||||||
bufstart = bufend-1;
|
bufstart = bufend-1;
|
||||||
break;
|
break;
|
||||||
|
case ':':
|
||||||
|
state = scoperes1;
|
||||||
|
break;
|
||||||
case '-':
|
case '-':
|
||||||
case '0':
|
case '0':
|
||||||
case '1':
|
case '1':
|
||||||
@@ -469,6 +478,19 @@ uint4 GrammarLexer::moveState(char lookahead)
|
|||||||
state = start;
|
state = start;
|
||||||
res = GrammarToken::dotdotdot;
|
res = GrammarToken::dotdotdot;
|
||||||
break;
|
break;
|
||||||
|
case scoperes1:
|
||||||
|
if (lookahead == ':') {
|
||||||
|
state = scoperes2;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
state = start;
|
||||||
|
res = ':';
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case scoperes2:
|
||||||
|
state = start;
|
||||||
|
res = GrammarToken::scoperes;
|
||||||
|
break;
|
||||||
case punctuation:
|
case punctuation:
|
||||||
state = start;
|
state = start;
|
||||||
res = (uint4)buffer[bufstart];
|
res = (uint4)buffer[bufstart];
|
||||||
@@ -529,7 +551,7 @@ uint4 GrammarLexer::moveState(char lookahead)
|
|||||||
}
|
}
|
||||||
else if ((lookahead>='a')&&(lookahead<='z')) {
|
else if ((lookahead>='a')&&(lookahead<='z')) {
|
||||||
}
|
}
|
||||||
else if (lookahead == '_' || lookahead == ':') {
|
else if (lookahead == '_') {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
state = start;
|
state = start;
|
||||||
@@ -1035,6 +1057,8 @@ Datatype *CParse::newStruct(const string &ident,vector<TypeDeclarator *> *declis
|
|||||||
{ // Build a new structure
|
{ // Build a new structure
|
||||||
TypeStruct *res = glb->types->getTypeStruct(ident); // Create stub (for recursion)
|
TypeStruct *res = glb->types->getTypeStruct(ident); // Create stub (for recursion)
|
||||||
vector<TypeField> sublist;
|
vector<TypeField> sublist;
|
||||||
|
vector<TypeBitField> bitlist;
|
||||||
|
bool isBigEndian = glb->getDefaultDataSpace()->isBigEndian();
|
||||||
|
|
||||||
for(uint4 i=0;i<declist->size();++i) {
|
for(uint4 i=0;i<declist->size();++i) {
|
||||||
TypeDeclarator *decl = (*declist)[i];
|
TypeDeclarator *decl = (*declist)[i];
|
||||||
@@ -1043,14 +1067,14 @@ Datatype *CParse::newStruct(const string &ident,vector<TypeDeclarator *> *declis
|
|||||||
glb->types->destroyType(res);
|
glb->types->destroyType(res);
|
||||||
return (Datatype *)0;
|
return (Datatype *)0;
|
||||||
}
|
}
|
||||||
|
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));
|
sublist.emplace_back(0,-1,decl->getIdentifier(),decl->buildType(glb));
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
int4 newSize;
|
glb->types->assignRawFields(res,sublist,bitlist);
|
||||||
int4 newAlign;
|
|
||||||
TypeStruct::assignFieldOffsets(sublist,newSize,newAlign);
|
|
||||||
glb->types->setFields(sublist,res,newSize,newAlign,0);
|
|
||||||
}
|
}
|
||||||
catch (LowlevelError &err) {
|
catch (LowlevelError &err) {
|
||||||
setError(err.explain);
|
setError(err.explain);
|
||||||
@@ -1086,10 +1110,7 @@ Datatype *CParse::newUnion(const string &ident,vector<TypeDeclarator *> *declist
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
int4 newSize;
|
glb->types->assignRawFields(res,sublist);
|
||||||
int4 newAlign;
|
|
||||||
TypeUnion::assignFieldOffsets(sublist,newSize,newAlign,res);
|
|
||||||
glb->types->setFields(sublist,res,newSize,newAlign,0);
|
|
||||||
}
|
}
|
||||||
catch (LowlevelError &err) {
|
catch (LowlevelError &err) {
|
||||||
setError(err.explain);
|
setError(err.explain);
|
||||||
@@ -1282,6 +1303,8 @@ int4 CParse::lex(void)
|
|||||||
return BADTOKEN;
|
return BADTOKEN;
|
||||||
case GrammarToken::dotdotdot:
|
case GrammarToken::dotdotdot:
|
||||||
return DOTDOTDOT;
|
return DOTDOTDOT;
|
||||||
|
case GrammarToken::scoperes:
|
||||||
|
return SCOPERES;
|
||||||
case GrammarToken::badtoken:
|
case GrammarToken::badtoken:
|
||||||
setError(lexer.getError()); // Error from lexer
|
setError(lexer.getError()); // Error from lexer
|
||||||
return BADTOKEN;
|
return BADTOKEN;
|
||||||
|
|||||||
@@ -1268,6 +1268,6 @@ ElementId ELEM_VAL = ElementId("val",8);
|
|||||||
ElementId ELEM_VALUE = ElementId("value",9);
|
ElementId ELEM_VALUE = ElementId("value",9);
|
||||||
ElementId ELEM_VOID = ElementId("void",10);
|
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
|
} // 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
|
/// 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.
|
/// 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 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
|
/// \return the result of applying \b this operation to the input values
|
||||||
uintb PcodeOp::executeSimple(uintb *in,bool &evalError) const
|
uintb PcodeOp::executeSimple(uintb *in,bool &evalError) const
|
||||||
|
|
||||||
@@ -732,8 +733,14 @@ uintb PcodeOp::getNZMaskLocal(bool cliploop) const
|
|||||||
case CPUI_INT_ADD:
|
case CPUI_INT_ADD:
|
||||||
resmask = getIn(0)->getNZMask();
|
resmask = getIn(0)->getNZMask();
|
||||||
if (resmask!=fullmask) {
|
if (resmask!=fullmask) {
|
||||||
resmask |= getIn(1)->getNZMask();
|
uintb othermask = getIn(1)->getNZMask();
|
||||||
resmask |= (resmask<<1); // Account for possible carries
|
if ((othermask & resmask) == 0) {
|
||||||
|
resmask |= othermask;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
resmask |= othermask;
|
||||||
|
resmask |= (resmask << 1); // Account for possible carries
|
||||||
|
}
|
||||||
resmask &= fullmask;
|
resmask &= fullmask;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -102,9 +102,10 @@ void OpBehavior::registerInstructions(vector<OpBehavior *> &inst,const Translate
|
|||||||
inst[CPUI_CPOOLREF] = new OpBehavior(CPUI_CPOOLREF,false,true);
|
inst[CPUI_CPOOLREF] = new OpBehavior(CPUI_CPOOLREF,false,true);
|
||||||
inst[CPUI_NEW] = new OpBehavior(CPUI_NEW,false,true);
|
inst[CPUI_NEW] = new OpBehavior(CPUI_NEW,false,true);
|
||||||
inst[CPUI_INSERT] = new OpBehavior(CPUI_INSERT,false);
|
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_POPCOUNT] = new OpBehaviorPopcount();
|
||||||
inst[CPUI_LZCOUNT] = new OpBehaviorLzcount();
|
inst[CPUI_LZCOUNT] = new OpBehaviorLzcount();
|
||||||
|
inst[CPUI_SPULL] = new OpBehavior(CPUI_SPULL,false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \param sizeout is the size of the output in bytes
|
/// \param sizeout is the size of the output in bytes
|
||||||
|
|||||||
@@ -123,11 +123,12 @@ enum OpCode {
|
|||||||
CPUI_CPOOLREF = 68, ///< Recover a value from the \e constant \e pool
|
CPUI_CPOOLREF = 68, ///< Recover a value from the \e constant \e pool
|
||||||
CPUI_NEW = 69, ///< Allocate a new object (new)
|
CPUI_NEW = 69, ///< Allocate a new object (new)
|
||||||
CPUI_INSERT = 70, ///< Insert a bit-range
|
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_POPCOUNT = 72, ///< Count the 1-bits
|
||||||
CPUI_LZCOUNT = 73, ///< Count the leading 0-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
|
extern const char *get_opname(OpCode opc); ///< Convert an OpCode to the name as a string
|
||||||
|
|||||||
@@ -252,6 +252,25 @@ void EmitMarkup::tagField(const string &name,syntax_highlight hl,const Datatype
|
|||||||
encoder->closeElement(ELEM_FIELD);
|
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)
|
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
|
case field_t: // tagField
|
||||||
emit->tagField(tok,hl,ptr_second.ct,(int4)off,op);
|
emit->tagField(tok,hl,ptr_second.ct,(int4)off,op);
|
||||||
break;
|
break;
|
||||||
|
case bitfield_t: // tagBitField
|
||||||
|
emit->tagBitField(tok,hl,ptr_second.ct,(int4)off,op);
|
||||||
|
break;
|
||||||
case comm_t: // tagComment
|
case comm_t: // tagComment
|
||||||
emit->tagComment(tok,hl,ptr_second.spc,off);
|
emit->tagComment(tok,hl,ptr_second.spc,off);
|
||||||
break;
|
break;
|
||||||
@@ -501,6 +523,9 @@ void TokenSplit::printDebug(ostream &s) const
|
|||||||
case field_t: // tagField
|
case field_t: // tagField
|
||||||
s << "field_t";
|
s << "field_t";
|
||||||
break;
|
break;
|
||||||
|
case bitfield_t: // tagBitField
|
||||||
|
s << "bitfield_t";
|
||||||
|
break;
|
||||||
case comm_t: // tagComment
|
case comm_t: // tagComment
|
||||||
s << "comm_t";
|
s << "comm_t";
|
||||||
break;
|
break;
|
||||||
@@ -1055,6 +1080,15 @@ void EmitPrettyPrint::tagField(const string &name,syntax_highlight hl,const Data
|
|||||||
scan();
|
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)
|
void EmitPrettyPrint::tagComment(const string &name,syntax_highlight hl,const AddrSpace *spc,uintb off)
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -273,11 +273,22 @@ public:
|
|||||||
/// possibly with additional markup.
|
/// possibly with additional markup.
|
||||||
/// \param name is the character data for the identifier
|
/// \param name is the character data for the identifier
|
||||||
/// \param hl indicates how the identifier should be highlighted
|
/// \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 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)
|
/// \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;
|
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
|
/// \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,
|
/// 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 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 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 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 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 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);
|
virtual void tagCaseLabel(const string &name,syntax_highlight hl,const PcodeOp *op,uintb value);
|
||||||
@@ -576,6 +588,8 @@ public:
|
|||||||
*s << name; }
|
*s << name; }
|
||||||
virtual void tagField(const string &name,syntax_highlight hl,const Datatype *ct,int4 off,const PcodeOp *op) {
|
virtual void tagField(const string &name,syntax_highlight hl,const Datatype *ct,int4 off,const PcodeOp *op) {
|
||||||
*s << name; }
|
*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) {
|
virtual void tagComment(const string &name,syntax_highlight hl,const AddrSpace *spc,uintb off) {
|
||||||
*s << name; }
|
*s << name; }
|
||||||
virtual void tagLabel(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) {
|
||||||
@@ -642,6 +656,7 @@ public:
|
|||||||
fnam_t, ///< A function identifier
|
fnam_t, ///< A function identifier
|
||||||
type_t, ///< A data-type identifier
|
type_t, ///< A data-type identifier
|
||||||
field_t, ///< A field name for a structured data-type
|
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
|
comm_t, ///< Part of a comment block
|
||||||
label_t, ///< A code label
|
label_t, ///< A code label
|
||||||
case_t, ///< A case label
|
case_t, ///< A case label
|
||||||
@@ -808,13 +823,24 @@ public:
|
|||||||
///
|
///
|
||||||
/// \param name is the character data for the identifier
|
/// \param name is the character data for the identifier
|
||||||
/// \param h indicates how the identifier should be highlighted
|
/// \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 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)
|
/// \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) {
|
void tagField(const string &name,EmitMarkup::syntax_highlight h,const Datatype *ct,int4 o,const PcodeOp *inOp) {
|
||||||
tok = name; size = tok.size();
|
tok = name; size = tok.size();
|
||||||
tagtype=field_t; delimtype=tokenstring; hl=h; ptr_second.ct=ct; off=(uintb)o; op=inOp; }
|
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
|
/// \brief Create a comment string in the generated source code
|
||||||
///
|
///
|
||||||
/// \param name is the character data for the comment
|
/// \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 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 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 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 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 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);
|
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;
|
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
|
/// 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).
|
/// 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,
|
/// 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)
|
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)
|
||||||
|
|
||||||
{
|
{
|
||||||
|
PullExpression expr(op);
|
||||||
|
if (!expr.isValid()) {
|
||||||
opFunc(op); // If no other way to print it, print as functional operator
|
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
|
/// \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;
|
ct = field->type;
|
||||||
succeeded = true;
|
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) {
|
else if (ct->getMetatype() == TYPE_ARRAY) {
|
||||||
int4 el;
|
int4 el;
|
||||||
@@ -2468,21 +2537,31 @@ bool PrintC::emitInplaceOp(const PcodeOp *op)
|
|||||||
void PrintC::emitExpression(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();
|
const Varnode *outvn = op->getOut();
|
||||||
if (outvn != (Varnode *)0) {
|
if (outvn != (Varnode *)0) {
|
||||||
if (option_inplace_ops && emitInplaceOp(op)) return;
|
if (option_inplace_ops && emitInplaceOp(op)) return;
|
||||||
pushOp(&assignment,op);
|
pushOp(&assignment,op);
|
||||||
pushSymbolDetail(outvn,op,false);
|
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 STORE, print *( ) = ( )
|
||||||
// If BRANCH, print nothing
|
// If BRANCH, print nothing
|
||||||
@@ -2494,6 +2573,62 @@ void PrintC::emitExpression(const PcodeOp *op)
|
|||||||
recurse();
|
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)
|
void PrintC::emitVarDecl(const Symbol *sym)
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -177,6 +177,7 @@ protected:
|
|||||||
virtual bool doEmitWideCharPrefix(void) const;
|
virtual bool doEmitWideCharPrefix(void) const;
|
||||||
|
|
||||||
bool checkArrayDeref(const Varnode *vn) const; ///< Determine whether a LOAD/STORE expression requires pointer '*' syntax
|
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 '&'
|
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 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
|
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 string genericTypeName(const Datatype *ct);
|
||||||
|
|
||||||
virtual void emitExpression(const PcodeOp *op);
|
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 emitVarDecl(const Symbol *sym);
|
||||||
virtual void emitVarDeclStatement(const Symbol *sym);
|
virtual void emitVarDeclStatement(const Symbol *sym);
|
||||||
virtual bool emitScopeVarDecls(const Scope *symScope,int4 cat);
|
virtual bool emitScopeVarDecls(const Scope *symScope,int4 cat);
|
||||||
@@ -339,7 +343,8 @@ public:
|
|||||||
virtual void opCpoolRefOp(const PcodeOp *op);
|
virtual void opCpoolRefOp(const PcodeOp *op);
|
||||||
virtual void opNewOp(const PcodeOp *op);
|
virtual void opNewOp(const PcodeOp *op);
|
||||||
virtual void opInsertOp(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 opPopcountOp(const PcodeOp *op) { opFunc(op); }
|
||||||
virtual void opLzcountOp(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:
|
case fieldtoken:
|
||||||
emit->tagField(atom.name,atom.highlight,atom.ptr_second.ct,atom.offset,atom.op);
|
emit->tagField(atom.name,atom.highlight,atom.ptr_second.ct,atom.offset,atom.op);
|
||||||
break;
|
break;
|
||||||
|
case bitfieldtoken:
|
||||||
|
emit->tagBitField(atom.name,atom.highlight,atom.ptr_second.ct,atom.offset,atom.op);
|
||||||
|
break;
|
||||||
case casetoken:
|
case casetoken:
|
||||||
emit->tagCaseLabel(atom.name, atom.highlight, atom.op, atom.ptr_second.intValue);
|
emit->tagCaseLabel(atom.name, atom.highlight, atom.op, atom.ptr_second.intValue);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -167,6 +167,7 @@ public:
|
|||||||
optoken, ///< Emit atom as operator
|
optoken, ///< Emit atom as operator
|
||||||
typetoken, ///< Emit atom as operator
|
typetoken, ///< Emit atom as operator
|
||||||
fieldtoken, ///< Emit atom as structure field
|
fieldtoken, ///< Emit atom as structure field
|
||||||
|
bitfieldtoken, ///< Emit atom as structure bitfield
|
||||||
casetoken, ///< Emit atom as a \e case label
|
casetoken, ///< Emit atom as a \e case label
|
||||||
blanktoken ///< For anonymous types
|
blanktoken ///< For anonymous types
|
||||||
};
|
};
|
||||||
@@ -429,6 +430,24 @@ protected:
|
|||||||
/// \param op is the given PcodeOp performing the final operation of the expression
|
/// \param op is the given PcodeOp performing the final operation of the expression
|
||||||
virtual void emitExpression(const PcodeOp *op)=0;
|
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
|
/// \brief Emit a function declaration
|
||||||
///
|
///
|
||||||
/// This prints the formal defining prototype for a function.
|
/// 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 opCpoolRefOp(const PcodeOp *op)=0; ///< Emit a CPOOLREF operator
|
||||||
virtual void opNewOp(const PcodeOp *op)=0; ///< Emit a NEW 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 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 opPopcountOp(const PcodeOp *op)=0; ///< Emit a POPCOUNT operator
|
||||||
virtual void opLzcountOp(const PcodeOp *op)=0; ///< Emit a LZCOUNT 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
|
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
|
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;
|
if (elType->getSize() < outSize + offset) return 0;
|
||||||
|
|
||||||
type_metatype meta = elType->getMetatype();
|
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);
|
bool addForm = checkAndComparison(outVn);
|
||||||
AddrSpace *spc = op->getIn(0)->getSpaceFromConst();
|
AddrSpace *spc = op->getIn(0)->getSpaceFromConst();
|
||||||
int4 lsbCut = 0;
|
int4 lsbCut = 0;
|
||||||
|
|||||||
@@ -2764,6 +2764,7 @@ bool SplitDatatype::splitLoad(PcodeOp *loadOp,Datatype *inType)
|
|||||||
if (copyOp != (PcodeOp *)0) {
|
if (copyOp != (PcodeOp *)0) {
|
||||||
OpCode opc = copyOp->code();
|
OpCode opc = copyOp->code();
|
||||||
if (opc == CPUI_STORE) return false; // Handled by RuleSplitStore
|
if (opc == CPUI_STORE) return false; // Handled by RuleSplitStore
|
||||||
|
if (opc == CPUI_ZPULL || opc == CPUI_SPULL) return false;
|
||||||
if (opc != CPUI_COPY)
|
if (opc != CPUI_COPY)
|
||||||
copyOp = (PcodeOp *)0;
|
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_USE_MS_CONVENTION; ///< Marshaling element \<use_MS_convention>
|
||||||
extern ElementId ELEM_WCHAR_SIZE; ///< Marshaling element \<wchar_size>
|
extern ElementId ELEM_WCHAR_SIZE; ///< Marshaling element \<wchar_size>
|
||||||
//extern ElementId ELEM_ZERO_LENGTH_BOUNDARY; ///< Marshaling element \<zero_length_boundary>
|
//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
|
/// Print a hex dump of a data buffer to stream
|
||||||
extern void print_data(ostream &s,uint1 *buffer,int4 size,const Address &baseaddr);
|
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 Architecture; // Forward declarations
|
||||||
class PcodeOp;
|
class PcodeOp;
|
||||||
class Scope;
|
class Scope;
|
||||||
|
class TypeStruct;
|
||||||
class TypeFactory;
|
class TypeFactory;
|
||||||
class TypeField;
|
class TypeField;
|
||||||
struct DatatypeCompare;
|
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
|
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
|
truncate_bigendian = 0x8000, ///< Pointer can be truncated and is big endian
|
||||||
pointer_to_array = 0x10000, ///< Data-type is a pointer to an array
|
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 class TypeFactory;
|
||||||
friend struct DatatypeCompare;
|
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 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 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 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 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
|
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
|
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
|
/// \return the i-th component sub-type
|
||||||
virtual Datatype *getDepend(int4 index) const { return (Datatype *)0; }
|
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
|
/// \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
|
/// 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
|
/// \brief A field within a structure or union
|
||||||
class TypeField {
|
class TypeField {
|
||||||
public:
|
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
|
int4 offset; ///< Offset (into containing structure or union) of subfield
|
||||||
string name; ///< Name of subfield
|
string name; ///< Name of subfield
|
||||||
Datatype *type; ///< Data-type of subfield
|
Datatype *type; ///< Data-type of subfield
|
||||||
TypeField(Decoder &decoder,TypeFactory &typegrp); ///< Restore \b this field from a stream
|
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
|
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
|
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
|
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
|
/// Compare two Datatype pointers for equivalence of their description
|
||||||
@@ -421,6 +469,7 @@ public:
|
|||||||
virtual Datatype *getSubType(int8 off,int8 *newoff) const;
|
virtual Datatype *getSubType(int8 off,int8 *newoff) const;
|
||||||
virtual int4 numDepend(void) const { return 1; }
|
virtual int4 numDepend(void) const { return 1; }
|
||||||
virtual Datatype *getDepend(int4 index) const { return ptrto; }
|
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 void printNameBase(ostream &s) const { s << 'p'; ptrto->printNameBase(s); }
|
||||||
virtual int4 compare(const Datatype &op,int4 level) const;
|
virtual int4 compare(const Datatype &op,int4 level) const;
|
||||||
virtual int4 compareDependency(const Datatype &op) const;
|
virtual int4 compareDependency(const Datatype &op) const;
|
||||||
@@ -508,16 +557,32 @@ public:
|
|||||||
class TypeStruct : public Datatype {
|
class TypeStruct : public Datatype {
|
||||||
protected:
|
protected:
|
||||||
friend class TypeFactory;
|
friend class TypeFactory;
|
||||||
vector<TypeField> field; ///< The list of fields
|
vector<TypeField> field; ///< List of fields
|
||||||
void setFields(const vector<TypeField> &fd,int4 fixedSize,int4 fixedAlign); ///< Establish fields for \b this
|
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 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
|
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
|
string decodeFields(Decoder &decoder,TypeFactory &typegrp); ///< Restore fields from a stream
|
||||||
|
static void assignContiguousBitfields(vector<TypeBitField> &bitlist,int4 &pos,int4 &offset,int4 &newAlign);
|
||||||
public:
|
public:
|
||||||
TypeStruct(const TypeStruct &op); ///< Construct from another TypeStruct
|
TypeStruct(const TypeStruct &op); ///< Construct from another TypeStruct
|
||||||
TypeStruct(void) : Datatype(0,-1,TYPE_STRUCT) { flags |= type_incomplete; } ///< Construct incomplete/empty 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 beginField(void) const { return field.begin(); } ///< Beginning of fields
|
||||||
vector<TypeField>::const_iterator endField(void) const { return field.end(); } ///< End 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 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 *getSubType(int8 off,int8 *newoff) const;
|
||||||
virtual Datatype *nearestArrayedComponentForward(int8 off,int8 *newoff,int8 *elSize) 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 *resolveInFlow(PcodeOp *op,int4 slot);
|
||||||
virtual Datatype* findResolve(const PcodeOp *op,int4 slot);
|
virtual Datatype* findResolve(const PcodeOp *op,int4 slot);
|
||||||
virtual int4 findCompatibleResolve(Datatype *ct) const;
|
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
|
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
|
/// \return the offset value in \e byte units
|
||||||
int4 getByteOffset(void) const { return offset; }
|
int4 getByteOffset(void) const { return offset; }
|
||||||
virtual void printRaw(ostream &s) const;
|
virtual void printRaw(ostream &s) const;
|
||||||
|
virtual Datatype *getPtrInto(int4 &off) const;
|
||||||
virtual int4 compare(const Datatype &op,int4 level) const;
|
virtual int4 compare(const Datatype &op,int4 level) const;
|
||||||
virtual int4 compareDependency(const Datatype &op) const;
|
virtual int4 compareDependency(const Datatype &op) const;
|
||||||
virtual Datatype *clone(void) const { return new TypePointerRel(*this); }
|
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 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 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 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:
|
protected:
|
||||||
Architecture *glb; ///< The Architecture object that owns this TypeFactory
|
Architecture *glb; ///< The Architecture object that owns this TypeFactory
|
||||||
Datatype *findByIdLocal(const string &nm,uint8 id) const; ///< Search locally by name and id
|
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 *findByName(const string &n); ///< Return type of given name
|
||||||
Datatype *setName(Datatype *ct,const string &n); ///< Set the given types 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 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 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
|
void setEnumValues(const map<uintb,string> &nmap,TypeEnum *te); ///< Set named values for an enumeration
|
||||||
Datatype *decodeType(Decoder &decoder); ///< Restore Datatype from a stream
|
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);
|
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 *getTypePointerWithSpace(Datatype *ptrTo,AddrSpace *spc,const string &nm);
|
||||||
TypePointer *resizePointer(TypePointer *ptr,int4 newSize); ///< Build a resized pointer based on the given pointer
|
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
|
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
|
void destroyType(Datatype *ct); ///< Remove a data-type from \b this
|
||||||
Datatype *concretize(Datatype *ct); ///< Convert given data-type to concrete form
|
Datatype *concretize(Datatype *ct); ///< Convert given data-type to concrete form
|
||||||
void dependentOrder(vector<Datatype *> &deporder) const; ///< Place all data-types in dependency order
|
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_CPOOLREF] = new TypeOpCpoolref(tlst);
|
||||||
inst[CPUI_NEW] = new TypeOpNew(tlst);
|
inst[CPUI_NEW] = new TypeOpNew(tlst);
|
||||||
inst[CPUI_INSERT] = new TypeOpInsert(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_POPCOUNT] = new TypeOpPopcount(tlst);
|
||||||
inst[CPUI_LZCOUNT] = new TypeOpLzcount(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 '>>>' )
|
/// 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 (slot==0) return (Datatype *)0;
|
||||||
|
if (op->doesSpecialPrinting()) return (Datatype *)0;
|
||||||
const Varnode *pointerVn = op->getIn(1);
|
const Varnode *pointerVn = op->getIn(1);
|
||||||
Datatype *pointerType = pointerVn->getHighTypeReadFacing(op);
|
Datatype *pointerType = pointerVn->getHighTypeReadFacing(op);
|
||||||
Datatype *pointedToType = pointerType;
|
Datatype *pointedToType = pointerType;
|
||||||
@@ -2535,19 +2537,31 @@ TypeOpInsert::TypeOpInsert(TypeFactory *t)
|
|||||||
Datatype *TypeOpInsert::getInputLocal(const PcodeOp *op,int4 slot) const
|
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 tlst->getBase(op->getIn(slot)->getSize(),TYPE_UNKNOWN);
|
||||||
return TypeOpFunc::getInputLocal(op, slot);
|
return TypeOpFunc::getInputLocal(op, slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeOpExtract::TypeOpExtract(TypeFactory *t)
|
Datatype *TypeOpInsert::getInputCast(const PcodeOp *op,int4 slot,const CastStrategy *castStrategy) const
|
||||||
: TypeOpFunc(t,CPUI_EXTRACT,"EXTRACT",TYPE_INT,TYPE_INT)
|
|
||||||
|
{
|
||||||
|
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;
|
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)
|
if (slot == 0)
|
||||||
@@ -2555,6 +2569,45 @@ Datatype *TypeOpExtract::getInputLocal(const PcodeOp *op,int4 slot) const
|
|||||||
return TypeOpFunc::getInputLocal(op, slot);
|
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)
|
TypeOpPopcount::TypeOpPopcount(TypeFactory *t)
|
||||||
: TypeOpFunc(t,CPUI_POPCOUNT,"POPCOUNT",TYPE_INT,TYPE_UNKNOWN)
|
: TypeOpFunc(t,CPUI_POPCOUNT,"POPCOUNT",TYPE_INT,TYPE_UNKNOWN)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -887,15 +887,29 @@ class TypeOpInsert : public TypeOpFunc {
|
|||||||
public:
|
public:
|
||||||
TypeOpInsert(TypeFactory *t); ///< Constructor
|
TypeOpInsert(TypeFactory *t); ///< Constructor
|
||||||
virtual Datatype *getInputLocal(const PcodeOp *op,int4 slot) const;
|
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); }
|
virtual void push(PrintLanguage *lng,const PcodeOp *op,const PcodeOp *readOp) const { lng->opInsertOp(op); }
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \brief Information about the EXTRACT op-code
|
/// \brief Information about the ZPULL op-code
|
||||||
class TypeOpExtract : public TypeOpFunc {
|
class TypeOpZpull : public TypeOpFunc {
|
||||||
public:
|
public:
|
||||||
TypeOpExtract(TypeFactory *t); ///< Constructor
|
TypeOpZpull(TypeFactory *t); ///< Constructor
|
||||||
virtual Datatype *getInputLocal(const PcodeOp *op,int4 slot) const;
|
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
|
/// \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
|
plug-in enabled, but if it is disabled for some reason, it can be enabled from within
|
||||||
a Code Browser by selecting the
|
a Code Browser by selecting the
|
||||||
<informalexample>
|
<informalexample>
|
||||||
<emphasis role="bold">File -> Configure</emphasis>
|
<emphasis role="bold">File -> Configure...</emphasis>
|
||||||
</informalexample>
|
</informalexample>
|
||||||
menu option, then clicking on the <emphasis>Configure</emphasis> link under the
|
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
|
<emphasis role="bold">Ghidra Core</emphasis> section and checking the box next to
|
||||||
@@ -2059,6 +2059,34 @@
|
|||||||
<link linkend="AnalysisSplitStruct">Splitting Structure Accesses</link>.
|
<link linkend="AnalysisSplitStruct">Splitting Structure Accesses</link>.
|
||||||
</para>
|
</para>
|
||||||
</sect4>
|
</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">
|
<sect4 id="TypeEnum">
|
||||||
<title>Enumeration</title>
|
<title>Enumeration</title>
|
||||||
<para>
|
<para>
|
||||||
@@ -2589,6 +2617,7 @@
|
|||||||
<informalexample>
|
<informalexample>
|
||||||
<itemizedlist mark='none'>
|
<itemizedlist mark='none'>
|
||||||
<listitem><emphasis>DEFAULT</emphasis> - for basic or no information</listitem>
|
<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>ANALYSIS</emphasis> - for information derived by an Analyzer</listitem>
|
||||||
<listitem><emphasis>IMPORTED</emphasis> - for information imported from an external source</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>
|
<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
|
this to <emphasis>off</emphasis> lets the user see the dead code, which is typically demarcated
|
||||||
by the control-flow structure:
|
by the control-flow structure:
|
||||||
<informalexample>
|
<informalexample>
|
||||||
<code>if (false) { ... }</code>
|
<programlisting>
|
||||||
|
if (false) { ... }
|
||||||
|
</programlisting>
|
||||||
</informalexample>
|
</informalexample>
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
@@ -3127,7 +3158,9 @@
|
|||||||
rendered using a standard <emphasis role="bold">for</emphasis> loop header
|
rendered using a standard <emphasis role="bold">for</emphasis> loop header
|
||||||
that contains an initializer statement, condition, and iterating statement.
|
that contains an initializer statement, condition, and iterating statement.
|
||||||
<informalexample>
|
<informalexample>
|
||||||
<code>for (iVar2 = 10; iVar2 < len; iVar2 = iVar2 + 1) { ...</code>
|
<programlisting>
|
||||||
|
for (iVar2 = 10; iVar2 < len; iVar2 = iVar2 + 1) { ...
|
||||||
|
</programlisting>
|
||||||
</informalexample>
|
</informalexample>
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
@@ -3158,6 +3191,24 @@
|
|||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</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">
|
<varlistentry id="AnalysisExtendedPrecision">
|
||||||
<term><emphasis role="bold">Simplify extended integer operations</emphasis></term>
|
<term><emphasis role="bold">Simplify extended integer operations</emphasis></term>
|
||||||
<listitem>
|
<listitem>
|
||||||
@@ -4962,7 +5013,7 @@
|
|||||||
<sect2 id="ActionEditOverride">
|
<sect2 id="ActionEditOverride">
|
||||||
<title>Edit Signature Override</title>
|
<title>Edit Signature Override</title>
|
||||||
<para>
|
<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>
|
||||||
<para>
|
<para>
|
||||||
This action can only be triggered at call sites with an existing signature override. As with the Override
|
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">
|
<article id="pcoderef_title">
|
||||||
<info>
|
<info>
|
||||||
<title>P-Code Reference Manual</title>
|
<title>P-Code Reference Manual</title>
|
||||||
<releaseinfo>Last updated March 2, 2023</releaseinfo>
|
<releaseinfo>Last updated January 16, 2026</releaseinfo>
|
||||||
</info>
|
</info>
|
||||||
<table xml:id="mytoc.htmltable" width="90%" frame='none'>
|
<table xml:id="mytoc.htmltable" width="90%" frame='none'>
|
||||||
<col width="25%"/>
|
<col width="25%"/>
|
||||||
@@ -307,7 +307,7 @@ at the destination address.
|
|||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
The list of possible
|
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,
|
each opcode is described in detail in the following sections,
|
||||||
and a reference table is given
|
and a reference table is given
|
||||||
in <xref linkend="reference"/>. In general, the size or
|
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
|
the indexed list of p-code operations corresponding to the translation
|
||||||
of the current machine instruction. This allows branching within the
|
of the current machine instruction. This allows branching within the
|
||||||
operations forming a single instruction. For example, if
|
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
|
operation with index 5 for the instruction, it can branch to operation
|
||||||
with index 8 by specifying a constant destination “address” of
|
with index 8 by specifying a constant destination “address” of
|
||||||
3. Negative constants can be used for backward branches.
|
3. Negative constants can be used for backward branches.
|
||||||
@@ -3908,26 +3908,29 @@ interpretation as a data-type changes at this point.
|
|||||||
</table>
|
</table>
|
||||||
</informalexample>
|
</informalexample>
|
||||||
<para>
|
<para>
|
||||||
The values <emphasis>position</emphasis> and <emphasis>size</emphasis> must be constants.
|
An <emphasis role="bold">INSERT</emphasis> operation takes the least significant
|
||||||
The least significant <emphasis>size</emphasis> bits from input1 are
|
<emphasis>size</emphasis> bits from input1 and inserts them into input0, overwriting
|
||||||
inserted into input0, overwriting a range of bits of the same size,
|
a range of bits of the same size, but leaving any other bits in input0 unchanged.
|
||||||
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.
|
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
This operation is never generated as raw p-code, even though it is equivalent
|
The least significant bit of the overwritten range is given by <emphasis>position</emphasis>,
|
||||||
to SLEIGH <emphasis role="bold">bitrange</emphasis> syntax such as input0[10,1] = input1.
|
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>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
<sect2 id="cpui_extract"><title>EXTRACT</title>
|
<sect2 id="cpui_zpull"><title>ZPULL</title>
|
||||||
<informalexample>
|
<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="23%"/>
|
||||||
<col width="15%"/>
|
<col width="15%"/>
|
||||||
<col width="61%"/>
|
<col width="61%"/>
|
||||||
@@ -3956,7 +3959,7 @@ to SLEIGH <emphasis role="bold">bitrange</emphasis> syntax such as input0[10,1]
|
|||||||
<tr>
|
<tr>
|
||||||
<td align='right'>output</td>
|
<td align='right'>output</td>
|
||||||
<td/>
|
<td/>
|
||||||
<td>Varnode result containing the extracted value.</td>
|
<td>Varnode containing the extracted value as an unsigned integer.</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
<tfoot>
|
<tfoot>
|
||||||
@@ -3972,19 +3975,90 @@ to SLEIGH <emphasis role="bold">bitrange</emphasis> syntax such as input0[10,1]
|
|||||||
</table>
|
</table>
|
||||||
</informalexample>
|
</informalexample>
|
||||||
<para>
|
<para>
|
||||||
The values <emphasis>position</emphasis> and <emphasis>size</emphasis> must be constants.
|
A <emphasis role="bold">ZPULL</emphasis> operation extracts <emphasis>size</emphasis> bits
|
||||||
The operation extracts <emphasis>size</emphasis> bits from input0 and returns it in output.
|
from input0 and returns them as an unsigned integer value in output, zero extending the
|
||||||
The <emphasis>position</emphasis> indicates the least significant bit in the range being extracted, with
|
bits to the size of output.
|
||||||
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.
|
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
This operation is never generated as raw p-code, even though it is equivalent
|
The <emphasis>position</emphasis> indicates the least significant bit in the range
|
||||||
to SLEIGH <emphasis role="bold">bitrange</emphasis> syntax such as output = input0[10,1].
|
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>
|
||||||
|
<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>
|
</sect2>
|
||||||
|
|
||||||
</sect1>
|
</sect1>
|
||||||
@@ -4096,7 +4170,7 @@ to SLEIGH <emphasis role="bold">bitrange</emphasis> syntax such as output = inpu
|
|||||||
<tr>
|
<tr>
|
||||||
<td>SUBPIECE</td>
|
<td>SUBPIECE</td>
|
||||||
<td><code>v0:2</code></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>
|
||||||
<tr>
|
<tr>
|
||||||
<td>SUBPIECE</td>
|
<td>SUBPIECE</td>
|
||||||
|
|||||||
@@ -677,7 +677,7 @@ define alignment=<emphasis role="bold">integer</emphasis>;
|
|||||||
</informalexample>
|
</informalexample>
|
||||||
This specifies the byte alignment of instructions within their address
|
This specifies the byte alignment of instructions within their address
|
||||||
space. It defaults to 1 or no alignment. When disassembling an
|
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
|
the address against this value and can opt to flag an unaligned
|
||||||
instruction as an error.
|
instruction as an error.
|
||||||
</para>
|
</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
|
or otherwise don't use an integral number of bytes. A recurring
|
||||||
example in many processors is the status register which is further
|
example in many processors is the status register which is further
|
||||||
subdivided into the overflow and result flags for the arithmetic
|
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
|
zero flag or CF for the carry flag and can be considered logical
|
||||||
registers contained within the status register. SLEIGH allows
|
registers contained within the status register. SLEIGH allows
|
||||||
registers to be defined like this using
|
registers to be defined like this using
|
||||||
@@ -1097,10 +1097,10 @@ We list all of the symbols that are predefined by SLEIGH.
|
|||||||
</informalexample>
|
</informalexample>
|
||||||
The most important of these to be aware of
|
The most important of these to be aware of
|
||||||
are <emphasis>inst_start</emphasis>
|
are <emphasis>inst_start</emphasis>
|
||||||
and <emphasis>inst_next</emphasis>. These are family symbols which map
|
and <emphasis>inst_next</emphasis>. These are family symbols that map
|
||||||
in the context of particular instruction to the integer offset of
|
to the integer offset of either the instruction's address or the next
|
||||||
either the address of the instruction or the address of the next
|
instruction's address, depending on the context of a particular instruction.
|
||||||
instruction respectively. These are used in any relative branching
|
These are used in any relative branching
|
||||||
situation. The <emphasis>inst_next2</emphasis> is intended for conditional
|
situation. The <emphasis>inst_next2</emphasis> is intended for conditional
|
||||||
skip instruction situations. The remaining symbols are rarely
|
skip instruction situations. The remaining symbols are rarely
|
||||||
used. The <emphasis>const</emphasis> and <emphasis>unique</emphasis>
|
used. The <emphasis>const</emphasis> and <emphasis>unique</emphasis>
|
||||||
@@ -1624,7 +1624,7 @@ field.
|
|||||||
<title>The '&' and '|' Operators</title>
|
<title>The '&' and '|' Operators</title>
|
||||||
<para>
|
<para>
|
||||||
More complicated patterns are built out of logical operators. The
|
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
|
constraints to be true at the same time, a <emphasis>logical
|
||||||
and</emphasis> ‘&’, or we can require that either one constraint or
|
and</emphasis> ‘&’, or we can require that either one constraint or
|
||||||
another must be true, a <emphasis>logical or</emphasis> ‘|’. By using these with
|
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>
|
<informalexample>
|
||||||
<programlisting>
|
<programlisting>
|
||||||
:xor r1,r2 is opcode=0xcd & r1 & r2 { r1 = r1 ^ r2; }
|
: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>
|
</programlisting>
|
||||||
</informalexample>
|
</informalexample>
|
||||||
</para>
|
</para>
|
||||||
@@ -1949,10 +1949,10 @@ feature of <emphasis>clr</emphasis> from <emphasis>xor</emphasis> is
|
|||||||
that the two fields, specifying the two register inputs
|
that the two fields, specifying the two register inputs
|
||||||
to <emphasis>xor</emphasis>, are equal. The easiest way to specify
|
to <emphasis>xor</emphasis>, are equal. The easiest way to specify
|
||||||
this special case is with the general constraint,
|
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
|
line of the example. The SLEIGH compiler will implement this by
|
||||||
enumerating all the cases where <emphasis>r2</emphasis>
|
enumerating all the cases where <emphasis>r1</emphasis>
|
||||||
equals <emphasis>r1</emphasis>, creating as many states as there are
|
equals <emphasis>r2</emphasis>, creating as many states as there are
|
||||||
registers. But the specification itself, at least, remains compact.
|
registers. But the specification itself, at least, remains compact.
|
||||||
</para>
|
</para>
|
||||||
</sect3>
|
</sect3>
|
||||||
|
|||||||
+33
-1
@@ -4,7 +4,7 @@
|
|||||||
<title>Program Annotations Affecting the Decompiler</title>
|
<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="help/shared/DefaultStyle.css">
|
||||||
<link rel="stylesheet" type="text/css" href="../../shared/languages.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="home" href="Decompiler.html" title="Decompiler">
|
||||||
<link rel="up" href="Decompiler.html" title="Decompiler">
|
<link rel="up" href="Decompiler.html" title="Decompiler">
|
||||||
<link rel="prev" href="DecompilerConcepts.html" title="Decompiler Concepts">
|
<link rel="prev" href="DecompilerConcepts.html" title="Decompiler Concepts">
|
||||||
@@ -710,6 +710,38 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="sect4">
|
<div class="sect4">
|
||||||
<div class="titlepage"><div><div><h5 class="title">
|
<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>
|
<a name="TypeEnum"></a>Enumeration</h5></div></div></div>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@
|
|||||||
<title>Decompiler Concepts</title>
|
<title>Decompiler Concepts</title>
|
||||||
<link rel="stylesheet" type="text/css" href="help/shared/DefaultStyle.css">
|
<link rel="stylesheet" type="text/css" href="help/shared/DefaultStyle.css">
|
||||||
<link rel="stylesheet" type="text/css" href="../../shared/languages.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="home" href="Decompiler.html" title="Decompiler">
|
||||||
<link rel="up" href="Decompiler.html" title="Decompiler">
|
<link rel="up" href="Decompiler.html" title="Decompiler">
|
||||||
<link rel="prev" href="DecompilerIntro.html" title="Decompiler">
|
<link rel="prev" href="DecompilerIntro.html" title="Decompiler">
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@
|
|||||||
<title>Decompiler</title>
|
<title>Decompiler</title>
|
||||||
<link rel="stylesheet" type="text/css" href="help/shared/DefaultStyle.css">
|
<link rel="stylesheet" type="text/css" href="help/shared/DefaultStyle.css">
|
||||||
<link rel="stylesheet" type="text/css" href="../../shared/languages.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="home" href="Decompiler.html" title="Decompiler">
|
||||||
<link rel="up" href="Decompiler.html" title="Decompiler">
|
<link rel="up" href="Decompiler.html" title="Decompiler">
|
||||||
<link rel="prev" href="Decompiler.html" title="Decompiler">
|
<link rel="prev" href="Decompiler.html" title="Decompiler">
|
||||||
|
|||||||
+31
-9
@@ -4,7 +4,7 @@
|
|||||||
<title>Decompiler Options</title>
|
<title>Decompiler Options</title>
|
||||||
<link rel="stylesheet" type="text/css" href="help/shared/DefaultStyle.css">
|
<link rel="stylesheet" type="text/css" href="help/shared/DefaultStyle.css">
|
||||||
<link rel="stylesheet" type="text/css" href="../../shared/languages.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="home" href="Decompiler.html" title="Decompiler">
|
||||||
<link rel="up" 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">
|
<link rel="prev" href="DecompilerAnnotations.html" title="Program Annotations Affecting the Decompiler">
|
||||||
@@ -206,7 +206,9 @@
|
|||||||
by the control-flow structure:
|
by the control-flow structure:
|
||||||
</p>
|
</p>
|
||||||
<div class="informalexample">
|
<div class="informalexample">
|
||||||
<code class="code">if (false) { ... }</code>
|
<pre class="programlisting">
|
||||||
|
if (false) { ... }
|
||||||
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
<p>
|
<p>
|
||||||
</p>
|
</p>
|
||||||
@@ -286,7 +288,9 @@
|
|||||||
that contains an initializer statement, condition, and iterating statement.
|
that contains an initializer statement, condition, and iterating statement.
|
||||||
</p>
|
</p>
|
||||||
<div class="informalexample">
|
<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>
|
</div>
|
||||||
<p>
|
<p>
|
||||||
</p>
|
</p>
|
||||||
@@ -318,6 +322,26 @@
|
|||||||
</p>
|
</p>
|
||||||
</dd>
|
</dd>
|
||||||
<dt>
|
<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>
|
<a name="AnalysisExtendedPrecision"></a><span class="term"><span class="bold"><strong>Simplify extended integer operations</strong></span></span>
|
||||||
</dt>
|
</dt>
|
||||||
<dd>
|
<dd>
|
||||||
@@ -534,16 +558,14 @@
|
|||||||
(see <a class="xref" href="DecompilerWindow.html#ActionFind" title="Find...">Find...</a>).
|
(see <a class="xref" href="DecompilerWindow.html#ActionFind" title="Find...">Find...</a>).
|
||||||
</p>
|
</p>
|
||||||
</dd>
|
</dd>
|
||||||
|
<dt>
|
||||||
<dt>
|
<a name="MiddleMouseColor"></a><span class="term"><span class="bold"><strong>Color for Highlighting Middle-mouse Matches</strong></span></span>
|
||||||
<a name="MiddleMouseColor"></a><span class="term"><span class="bold"><strong>Color for Highlighting Middle-mouse Matches</strong></span></span>
|
</dt>
|
||||||
</dt>
|
<dd>
|
||||||
<dd>
|
|
||||||
<p>
|
<p>
|
||||||
Assign the background color used to highlight characters when highlighting using the middle-mouse button.
|
Assign the background color used to highlight characters when highlighting using the middle-mouse button.
|
||||||
</p>
|
</p>
|
||||||
</dd>
|
</dd>
|
||||||
|
|
||||||
<dt>
|
<dt>
|
||||||
<a name="DisplayCommentIndent"></a><span class="term"><span class="bold"><strong>Comment line indent level</strong></span></span>
|
<a name="DisplayCommentIndent"></a><span class="term"><span class="bold"><strong>Comment line indent level</strong></span></span>
|
||||||
</dt>
|
</dt>
|
||||||
|
|||||||
+4
-5
@@ -4,7 +4,7 @@
|
|||||||
<title>Decompiler Window</title>
|
<title>Decompiler Window</title>
|
||||||
<link rel="stylesheet" type="text/css" href="help/shared/DefaultStyle.css">
|
<link rel="stylesheet" type="text/css" href="help/shared/DefaultStyle.css">
|
||||||
<link rel="stylesheet" type="text/css" href="../../shared/languages.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="home" href="Decompiler.html" title="Decompiler">
|
||||||
<link rel="up" href="Decompiler.html" title="Decompiler">
|
<link rel="up" href="Decompiler.html" title="Decompiler">
|
||||||
<link rel="prev" href="DecompilerOptions.html" title="Decompiler Options">
|
<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
|
token, within the Decompiler window. There are actions available from the popup menu and from
|
||||||
the keyboard to navigate to each highlighted token.
|
the keyboard to navigate to each highlighted token.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@@ -966,9 +965,9 @@
|
|||||||
|
|
||||||
<p>
|
<p>
|
||||||
These actions are available from the popup menu and keyboard. Only tokens highlighted from 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
|
middle-mouse will be navigated. <span class="bold"><strong>Shift-Comma</strong></span> will go to the
|
||||||
go to the previous highlighted token. <span class="bold"><strong>Shift-Period</strong></span>
|
previous highlighted token. <span class="bold"><strong>Shift-Period</strong></span> will go to the
|
||||||
will go to the next highlighted token. These key bindings can be changed via 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>.
|
<a class="ulink" href="help/topics/Tool/ToolOptions_Dialog.htm#KeyBindings_Option" target="_top">Tool Options Dialog</a>.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -259,6 +259,9 @@ public class ClangToken implements ClangNode {
|
|||||||
else if (node == ELEM_FIELD.id()) {
|
else if (node == ELEM_FIELD.id()) {
|
||||||
token = new ClangFieldToken(par);
|
token = new ClangFieldToken(par);
|
||||||
}
|
}
|
||||||
|
else if (node == ELEM_BITFIELD.id()) {
|
||||||
|
token = new ClangBitFieldToken(par);
|
||||||
|
}
|
||||||
else if (node == ELEM_VALUE.id()) {
|
else if (node == ELEM_VALUE.id()) {
|
||||||
token = new ClangCaseToken(par);
|
token = new ClangCaseToken(par);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -202,6 +202,13 @@ public class DecompileOptions {
|
|||||||
private final static AliasBlockEnum ALIASBLOCK_OPTIONDEFAULT = AliasBlockEnum.Array; // Must match Architecture::resetDefaultsInternal
|
private final static AliasBlockEnum ALIASBLOCK_OPTIONDEFAULT = AliasBlockEnum.Array; // Must match Architecture::resetDefaultsInternal
|
||||||
private AliasBlockEnum aliasBlock;
|
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_OPTIONSTRING = "Display.Print calling convention name";
|
||||||
private final static String CONVENTION_OPTIONDESCRIPTION =
|
private final static String CONVENTION_OPTIONDESCRIPTION =
|
||||||
"If set, the names of calling conventions (when they differ " +
|
"If set, the names of calling conventions (when they differ " +
|
||||||
@@ -499,6 +506,7 @@ public class DecompileOptions {
|
|||||||
nullToken = NULLTOKEN_OPTIONDEFAULT;
|
nullToken = NULLTOKEN_OPTIONDEFAULT;
|
||||||
inplaceTokens = INPLACEOP_OPTIONDEFAULT;
|
inplaceTokens = INPLACEOP_OPTIONDEFAULT;
|
||||||
aliasBlock = ALIASBLOCK_OPTIONDEFAULT;
|
aliasBlock = ALIASBLOCK_OPTIONDEFAULT;
|
||||||
|
bitfieldAccess = BITFIELD_OPTIONDEFAULT;
|
||||||
conventionPrint = CONVENTION_OPTIONDEFAULT;
|
conventionPrint = CONVENTION_OPTIONDEFAULT;
|
||||||
noCastPrint = NOCAST_OPTIONDEFAULT;
|
noCastPrint = NOCAST_OPTIONDEFAULT;
|
||||||
braceFunction = BRACEFUNCTION_OPTIONDEFAULT;
|
braceFunction = BRACEFUNCTION_OPTIONDEFAULT;
|
||||||
@@ -563,6 +571,7 @@ public class DecompileOptions {
|
|||||||
nullToken = opt.getBoolean(NULLTOKEN_OPTIONSTRING, NULLTOKEN_OPTIONDEFAULT);
|
nullToken = opt.getBoolean(NULLTOKEN_OPTIONSTRING, NULLTOKEN_OPTIONDEFAULT);
|
||||||
inplaceTokens = opt.getBoolean(INPLACEOP_OPTIONSTRING, INPLACEOP_OPTIONDEFAULT);
|
inplaceTokens = opt.getBoolean(INPLACEOP_OPTIONSTRING, INPLACEOP_OPTIONDEFAULT);
|
||||||
aliasBlock = opt.getEnum(ALIASBLOCK_OPTIONSTRING, ALIASBLOCK_OPTIONDEFAULT);
|
aliasBlock = opt.getEnum(ALIASBLOCK_OPTIONSTRING, ALIASBLOCK_OPTIONDEFAULT);
|
||||||
|
bitfieldAccess = opt.getBoolean(BITFIELD_OPTIONSTRING, BITFIELD_OPTIONDEFAULT);
|
||||||
conventionPrint = opt.getBoolean(CONVENTION_OPTIONSTRING, CONVENTION_OPTIONDEFAULT);
|
conventionPrint = opt.getBoolean(CONVENTION_OPTIONSTRING, CONVENTION_OPTIONDEFAULT);
|
||||||
noCastPrint = opt.getBoolean(NOCAST_OPTIONSTRING, NOCAST_OPTIONDEFAULT);
|
noCastPrint = opt.getBoolean(NOCAST_OPTIONSTRING, NOCAST_OPTIONDEFAULT);
|
||||||
braceFunction = opt.getEnum(BRACEFUNCTION_OPTIONSTRING, BRACEFUNCTION_OPTIONDEFAULT);
|
braceFunction = opt.getEnum(BRACEFUNCTION_OPTIONSTRING, BRACEFUNCTION_OPTIONDEFAULT);
|
||||||
@@ -693,6 +702,9 @@ public class DecompileOptions {
|
|||||||
opt.registerOption(ALIASBLOCK_OPTIONSTRING, ALIASBLOCK_OPTIONDEFAULT,
|
opt.registerOption(ALIASBLOCK_OPTIONSTRING, ALIASBLOCK_OPTIONDEFAULT,
|
||||||
new HelpLocation(HelpTopics.DECOMPILER, "AnalysisAliasBlocking"),
|
new HelpLocation(HelpTopics.DECOMPILER, "AnalysisAliasBlocking"),
|
||||||
ALIASBLOCK_OPTIONDESCRIPTION);
|
ALIASBLOCK_OPTIONDESCRIPTION);
|
||||||
|
opt.registerOption(BITFIELD_OPTIONSTRING, BITFIELD_OPTIONDEFAULT,
|
||||||
|
new HelpLocation(HelpTopics.DECOMPILER, "AnalysisBitfields"),
|
||||||
|
BITFIELD_OPTIONDESCRIPTION);
|
||||||
opt.registerOption(CONVENTION_OPTIONSTRING, CONVENTION_OPTIONDEFAULT,
|
opt.registerOption(CONVENTION_OPTIONSTRING, CONVENTION_OPTIONDEFAULT,
|
||||||
new HelpLocation(HelpTopics.DECOMPILER, "DisplayConvention"),
|
new HelpLocation(HelpTopics.DECOMPILER, "DisplayConvention"),
|
||||||
CONVENTION_OPTIONDESCRIPTION);
|
CONVENTION_OPTIONDESCRIPTION);
|
||||||
@@ -892,6 +904,10 @@ public class DecompileOptions {
|
|||||||
if (aliasBlock != ALIASBLOCK_OPTIONDEFAULT) {
|
if (aliasBlock != ALIASBLOCK_OPTIONDEFAULT) {
|
||||||
appendOption(encoder, ELEM_ALIASBLOCK, aliasBlock.getOptionString(), "", "");
|
appendOption(encoder, ELEM_ALIASBLOCK, aliasBlock.getOptionString(), "", "");
|
||||||
}
|
}
|
||||||
|
if (bitfieldAccess != BITFIELD_OPTIONDEFAULT) {
|
||||||
|
appendOption(encoder, ELEM_CURRENTACTION, "bitfields", bitfieldAccess ? "on" : "off",
|
||||||
|
"");
|
||||||
|
}
|
||||||
if (conventionPrint != CONVENTION_OPTIONDEFAULT) {
|
if (conventionPrint != CONVENTION_OPTIONDEFAULT) {
|
||||||
appendOption(encoder, ELEM_CONVENTIONPRINTING, conventionPrint ? "on" : "off", "", "");
|
appendOption(encoder, ELEM_CONVENTIONPRINTING, conventionPrint ? "on" : "off", "", "");
|
||||||
}
|
}
|
||||||
@@ -1664,6 +1680,22 @@ public class DecompileOptions {
|
|||||||
this.aliasBlock = aliasBlock;
|
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.}
|
* {@return number of characters per indent level.}
|
||||||
*/
|
*/
|
||||||
|
|||||||
+4
@@ -950,6 +950,9 @@ public class DecompilerProvider extends NavigatableComponentProviderAdapter
|
|||||||
RenameFieldAction renameFieldAction = new RenameFieldAction();
|
RenameFieldAction renameFieldAction = new RenameFieldAction();
|
||||||
setGroupInfo(renameFieldAction, variableGroup, subGroupPosition++);
|
setGroupInfo(renameFieldAction, variableGroup, subGroupPosition++);
|
||||||
|
|
||||||
|
RenameBitFieldAction renameBitFieldAction = new RenameBitFieldAction();
|
||||||
|
setGroupInfo(renameBitFieldAction, variableGroup, subGroupPosition++);
|
||||||
|
|
||||||
ForceUnionAction forceUnionAction = new ForceUnionAction();
|
ForceUnionAction forceUnionAction = new ForceUnionAction();
|
||||||
setGroupInfo(forceUnionAction, variableGroup, subGroupPosition++);
|
setGroupInfo(forceUnionAction, variableGroup, subGroupPosition++);
|
||||||
|
|
||||||
@@ -1148,6 +1151,7 @@ public class DecompilerProvider extends NavigatableComponentProviderAdapter
|
|||||||
addLocalAction(renameLocalAction);
|
addLocalAction(renameLocalAction);
|
||||||
addLocalAction(renameGlobalAction);
|
addLocalAction(renameGlobalAction);
|
||||||
addLocalAction(renameFieldAction);
|
addLocalAction(renameFieldAction);
|
||||||
|
addLocalAction(renameBitFieldAction);
|
||||||
addLocalAction(forceUnionAction);
|
addLocalAction(forceUnionAction);
|
||||||
addLocalAction(setSecondaryHighlightAction);
|
addLocalAction(setSecondaryHighlightAction);
|
||||||
addLocalAction(setSecondaryHighlightColorChooserAction);
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-1
@@ -102,9 +102,10 @@ public class OpBehaviorFactory {
|
|||||||
opBehaviorMap.put(PcodeOp.CPOOLREF, new SpecialOpBehavior(PcodeOp.CPOOLREF));
|
opBehaviorMap.put(PcodeOp.CPOOLREF, new SpecialOpBehavior(PcodeOp.CPOOLREF));
|
||||||
opBehaviorMap.put(PcodeOp.NEW, new SpecialOpBehavior(PcodeOp.NEW));
|
opBehaviorMap.put(PcodeOp.NEW, new SpecialOpBehavior(PcodeOp.NEW));
|
||||||
opBehaviorMap.put(PcodeOp.INSERT, new SpecialOpBehavior(PcodeOp.INSERT));
|
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.POPCOUNT, new OpBehaviorPopcount());
|
||||||
opBehaviorMap.put(PcodeOp.LZCOUNT, new OpBehaviorLzcount());
|
opBehaviorMap.put(PcodeOp.LZCOUNT, new OpBehaviorLzcount());
|
||||||
|
opBehaviorMap.put(PcodeOp.SPULL, new SpecialOpBehavior(PcodeOp.SPULL));
|
||||||
}
|
}
|
||||||
|
|
||||||
private OpBehaviorFactory() {
|
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