Merge remote-tracking branch 'origin/GP-6936_caheckman_WrappedRange' into patch

This commit is contained in:
Ryan Kurtz
2026-06-11 11:36:37 -04:00
9 changed files with 118 additions and 20 deletions

View File

@@ -94,6 +94,7 @@ src/decompile/datatests/twodim.xml||GHIDRA||||END|
src/decompile/datatests/union_datatype.xml||GHIDRA||||END|
src/decompile/datatests/varcross.xml||GHIDRA||||END|
src/decompile/datatests/wayoffarray.xml||GHIDRA||||END|
src/decompile/datatests/wraprange.xml||GHIDRA||||END|
src/decompile/zlib/README.txt||GHIDRA||||END|
src/main/doc/commonprofile.xsl||GHIDRA||||END|
src/main/doc/cspec.xml||GHIDRA||||END|

View File

@@ -87,6 +87,7 @@ public:
Address operator+(int8 off) const; ///< Increment address by a number of bytes
Address operator-(int8 off) const; ///< Decrement address by a number of bytes
friend ostream &operator<<(ostream &s,const Address &addr); ///< Write out an address to stream
bool isValidRange(uint8 size) const; ///< Is the range properly contained in its address space
bool containedBy(int4 sz,const Address &op2,int4 sz2) const; ///< Determine if \e op2 range contains \b this range
int4 justifiedContain(int4 sz,const Address &op2,int4 sz2,bool forceleft) const; ///< Determine if \e op2 is the least significant part of \e this.
int4 overlap(int4 skip,const Address &op,int4 size) const; ///< Determine how \b this address falls in a given address range
@@ -465,6 +466,14 @@ inline Address Address::operator-(int8 off) const {
return Address(base,base->wrapOffset(offset-off));
}
/// If the range starting at \b this address and extending for \b size bytes, encompasses bytes beyond
/// the edge of the address space (or wraps), then return \b false.
/// \param size is the number of bytes in the range (must be non-zero)
/// \return \b true if the range is properly contained in the address space
inline bool Address::isValidRange(uint8 size) const {
return (size-1) <= (base->getHighest() - offset);
}
/// This method is equivalent to Address::overlap, but a range in the \e join space can be
/// considered overlapped with its constituent pieces.
/// If \e this + \e skip falls in the range, \e op to \e op + \e size, then a non-negative integer is

View File

@@ -104,8 +104,15 @@ Varnode *Funcdata::newUnique(int4 s,Datatype *ct)
Varnode *Funcdata::newVarnodeOut(int4 s,const Address &m,PcodeOp *op)
{
Varnode *vn;
Datatype *ct = glb->types->getBase(s,TYPE_UNKNOWN);
Varnode *vn = vbank.createDef(s,m,ct,op);
if (m.isValidRange(s)) {
vn = vbank.createDef(s,m,ct,op);
}
else {
Address addr = glb->constructWrappingAddress(m, s);
vn = vbank.createDef(s,addr,ct,op);
}
op->setOutput(vn);
assignHigh(vn);
@@ -152,8 +159,13 @@ Varnode *Funcdata::newVarnode(int4 s,const Address &m,Datatype *ct)
if (ct == (const Datatype *)0)
ct = glb->types->getBase(s,TYPE_UNKNOWN);
vn = vbank.create(s,m,ct);
if (m.isValidRange(s)) {
vn = vbank.create(s,m,ct);
}
else {
Address addr = glb->constructWrappingAddress(m, s);
vn = vbank.create(s,addr,ct);
}
assignHigh(vn);
if (s >= minLanedSize)

View File

@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -94,7 +94,8 @@ public:
truncated = 0x100, ///< Space is truncated from its original size, expect pointers larger than this size
hasphysical = 0x200, ///< Has physical memory associated with it
is_otherspace = 0x400, ///< Quick check for the OtherSpace derived class
has_nearpointers = 0x800 ///< Does there exist near pointers into this space
has_nearpointers = 0x800, ///< Does there exist near pointers into this space
allows_wrapped_range = 0x1000 ///< A memory range for \b this space can wrap from high addresses to low
};
private:
spacetype type; ///< Type of space (PROCESSOR, CONSTANT, INTERNAL, ...)
@@ -150,6 +151,7 @@ public:
bool isOtherSpace(void) const; ///< Return \b true if \b this is the \e other address space
bool isTruncated(void) const; ///< Return \b true if this space is truncated from its original size
bool hasNearPointers(void) const; ///< Return \b true if \e near (truncated) pointers into \b this space are possible
bool allowsWrappedRange(void) const; ///< Return \b true if memory range can span high to low addresses in \b this space
void printOffset(ostream &s,uintb offset) const; ///< Write an address offset to a stream
virtual int4 numSpacebase(void) const; ///< Number of base registers associated with this space
@@ -467,6 +469,10 @@ inline bool AddrSpace::hasNearPointers(void) const {
return ((flags&has_nearpointers)!=0);
}
inline bool AddrSpace::allowsWrappedRange(void) const {
return ((flags & allows_wrapped_range)!=0);
}
/// Some spaces are "virtual", like the stack spaces, where addresses are really relative to a
/// base pointer stored in a register, like the stackpointer. This routine will return non-zero
/// if \b this space is virtual and there is 1 (or more) associated pointer registers

View File

@@ -61,6 +61,7 @@ SpacebaseSpace::SpacebaseSpace(AddrSpaceManager *m,const Translate *t,const stri
contain = base;
hasbaseregister = false; // No base register assigned yet
isNegativeStack = true; // default stack growth
setFlags(allows_wrapped_range);
if (isFormal)
setFlags(formal_stackspace);
}
@@ -73,9 +74,10 @@ SpacebaseSpace::SpacebaseSpace(AddrSpaceManager *m,const Translate *t,const stri
SpacebaseSpace::SpacebaseSpace(AddrSpaceManager *m,const Translate *t)
: AddrSpace(m,t,IPTR_SPACEBASE)
{
contain = (AddrSpace *)0;
hasbaseregister = false;
isNegativeStack = true;
setFlags(programspecific);
setFlags(programspecific | allows_wrapped_range);
}
/// This routine sets the base register associated with this \b virtual space
@@ -847,6 +849,38 @@ Address AddrSpaceManager::constructJoinAddress(const Translate *translate,
return join->getUnified().getAddr();
}
/// Check if the address space allows wrapped ranges. If so, construct a \e joined address
/// out of the high address piece of the range and the low address piece.
/// \param addr is the initial address in the range
/// \param size is the number of bytes in the range
/// \return the address representing the wrapped range
Address AddrSpaceManager::constructWrappingAddress(const Address &addr,int4 size)
{
AddrSpace *spc = addr.getSpace();
if (!spc->isHeritaged())
return addr; // Size is ignored
uintb dist = spc->getHighest() - addr.getOffset() + 1;
if (size <= dist)
return addr;
if (!spc->allowsWrappedRange())
throw LowlevelError("Trying to construct memory range beyond end of address space: "+spc->getName());
int4 sizehi = (int4)dist;
int4 sizelo = size - sizehi;
vector<VarnodeData> pieces;
pieces.emplace_back();
pieces.emplace_back();
int4 highIndex = spc->isBigEndian() ? 0 : 1;
pieces[highIndex].space = spc;
pieces[highIndex].offset = addr.getOffset();
pieces[highIndex].size = sizehi;
pieces[1-highIndex].space = spc;
pieces[1-highIndex].offset = 0;
pieces[1-highIndex].size = sizelo;
JoinRecord *join = findAddJoin(pieces,0);
return join->getUnified().getAddr();
}
/// If an Address in the \e join AddressSpace is shifted from its original offset, it may no
/// longer have a valid JoinRecord. The shift or size change may even make the address of
/// one of the pieces a more natural representation. Given a new Address and size, this method

View File

@@ -278,6 +278,9 @@ public:
/// \brief Build a logical whole from register pairs
Address constructJoinAddress(const Translate *translate,const Address &hiaddr,int4 hisz,const Address &loaddr,int4 losz);
/// \brief Build a logical whole representing a range that \e wraps from a high address to a low address
Address constructWrappingAddress(const Address &addr,int4 size);
/// \brief Make sure a possibly offset \e join address has a proper JoinRecord
void renormalizeJoinAddress(Address &addr,int4 size);

View File

@@ -120,6 +120,26 @@ void print_data(ostream &s,uint1 *buffer,int4 size,const Address &baseaddr)
}
}
/// Construct a data-type providing just the size, alignment, and meta-type.
/// Sets up the default configuration, which may be overridden by the derived constructor.
/// \param s is the size in bytes
/// \param align is the byte alignment required for \b this
/// \param m is the meta-type
Datatype::Datatype(int4 s,int4 align,type_metatype m)
{
if (s < 0)
throw LowlevelError("Bad data-type size");
size = s;
metatype = m;
submeta = base2sub[m];
flags = 0;
id = 0;
typedefImm = (Datatype *)0;
alignment = align;
alignSize = s;
}
/// If \b this and the other given data-type are both variable length and come from the
/// the same base data-type, return \b true.
/// \param ct is the other given data-type to compare with \b this
@@ -4052,7 +4072,7 @@ Datatype *TypeFactory::getBase(int4 s,type_metatype m)
{
Datatype *ct;
if (s<9) {
if ((uint4)s<9) {
if (m >= TYPE_FLOAT) {
ct = typecache[s][m-TYPE_FLOAT];
if (ct != (Datatype *)0)
@@ -4061,13 +4081,9 @@ Datatype *TypeFactory::getBase(int4 s,type_metatype m)
}
else if (m==TYPE_FLOAT) {
if (s==10)
ct = typecache10;
else if (s==16)
ct = typecache16;
else
ct = (Datatype *)0;
if (ct != (Datatype *)0)
return ct;
return typecache10;
if (s==16)
return typecache16;
}
if (s > glb->max_basetype_size) {
// Create array of unknown bytes to match size
@@ -4098,7 +4114,7 @@ Datatype *TypeFactory::getBase(int4 s,type_metatype m,const string &n)
Datatype *TypeFactory::getTypeChar(int4 s)
{
if (s < 5) {
if ((uint4)s < 5) {
Datatype *res = charcache[s];
if (res != (Datatype *)0)
return res;

View File

@@ -210,12 +210,10 @@ protected:
protected:
static int4 calcAlignSize(int4 sz,int4 align); ///< Calculate aligned size, given size and alignment of data-type
public:
/// Construct the base data-type copying low-level properties of another
/// \brief Construct the base data-type copying low-level properties of another
Datatype(const Datatype &op) { size = op.size; name=op.name; displayName=op.displayName; metatype=op.metatype;
submeta=op.submeta; flags=op.flags; id=op.id; typedefImm=op.typedefImm; alignment=op.alignment; alignSize=op.alignSize; }
/// Construct the base data-type providing size and meta-type
Datatype(int4 s,int4 align,type_metatype m) {
size=s; metatype=m; submeta=base2sub[m]; flags=0; id=0; typedefImm=(Datatype *)0; alignment=align; alignSize=s; }
Datatype(int4 s,int4 align,type_metatype m); ///< Constructor
virtual ~Datatype(void) {} ///< Destructor
bool isCoreType(void) const { return ((flags&coretype)!=0); } ///< Is this a core data-type
bool isCharPrint(void) const { return ((flags&(chartype|utf16|utf32|opaque_string))!=0); } ///< Does this print as a 'char'

View File

@@ -0,0 +1,19 @@
<decompilertest>
<!--
Example of accessing a stack range from high addresses to low addresses
-->
<binaryimage arch="x86:LE:64:default:gcc">
<bytechunk space="ram" offset="0x172390" readonly="true">
4883ec04488b04244883c404c3
</bytechunk>
<symbol space="ram" offset="0x172390" name="wraprange"/>
</binaryimage>
<script>
<com>load function wraprange</com>
<com>decompile</com>
<com>print raw</com>
<com>quit</com>
</script>
<stringmatch name="Wrapped range #1" min="1" max="1">j\{0x00000000,0xfffffffffffffffc\}.* = CONCAT44\(s0x00000000:4\(i\),s0xfffffffffffffffc:4\(i\)\)</stringmatch>
<stringmatch name="Wrapped range #2" min="1" max="1">RAX\(.*\) = j\{0x00000000,0xfffffffffffffffc\}</stringmatch>
</decompilertest>